I have a netgain hyper9 motor and controller. Controller is hooked up to CAN bus. I am using an esp32 with mcp2515 to read the data. The format is as in the image here.
I can read a byte ok and get a number but can not correctly read the word (2bytes) nor can I get the correct bitmap.
I am using esphome to read this through a lambda function.
Are there any c++ / esphome lambda people that could help?
WORD FORMAT: All words are sent in Little-endian format which reverses the order and stores the least significant byte at the lower memory address with the most significant byte being stored at the highest memory address.
byte word format:
reading a bitmask:
reading rpm through 2 byte word:
canbus:
- platform: mcp2515
id: my_mcp2515
spi_id: McpSpi
cs_pin: GPIO14
can_id: 2
use_extended_id: false
bit_rate: 250KBPS
clock: 8MHZ
mode: NORMAL
on_frame:
- can_id: 0x301 #[canbus:066]: received can message std can_id=0x301 size=8
use_extended_id: false
then:
- lambda: |-
//State of Charge - works ok
int soc = x[2];
id(motor_battery_soc).publish_state(soc);
//RPM - word format
std::string r1 = to_string(x[0]);
std::string r2 = to_string(x[1]);
std::string rpmString = r2 + r1;
id(motor_rpm).publish_state(rpmString);
//System flags
ESP_LOGD("system_flags x3: ", "%d", x[3] );
ESP_LOGD("system_flags x4: ", "%d", x[4] );
std::string sf1 = to_string(x[3]);
std::string sf2 = to_string(x[4]);
std::string sfString = sf2 + sf1;
std::string sflag = " ";
ESP_LOGD("main", "sfString: %s", sfString);
// *** I know this is not correct because should search for a true/false flag on the bitmask ***
int sfInt = atoi(sfString.c_str());
ESP_LOGD("sfInt: ", "%d", sfInt);
switch(sfInt) {
case 0:
sflag = "SoC is Low For Traction";
id(motor_system_flags).publish_state("SoC is Low For Traction");
break;
case 1:
sflag = "SoC is Low For Hydraulic";
id(motor_system_flags).publish_state("SoC is Low For Hydraulic");
break;
case 2:
sflag = "Reverse Direction Active";
id(motor_system_flags).publish_state("Reverse Direction Active");
break;
case 3:
sflag = "Forward Direction Active";
id(motor_system_flags).publish_state("Forward Direction Active");
break;
case 4:
sflag = "Park Brake Active";
id(motor_system_flags).publish_state("Park Brake Active");
break;
case 5:
sflag = "Pedal Brake Active";
id(motor_system_flags).publish_state("Pedal Brake Active");
break;
case 6:
sflag = "Controller is in Overtemperature";
id(motor_system_flags).publish_state("Controller is in Overtemperature");
break;
case 7:
sflag = "Key Switch Overvoltage";
id(motor_system_flags).publish_state("Key Switch Overvoltage");
break;
case 8:
sflag = "Key Switch Undervoltage";
id(motor_system_flags).publish_state("Key Switch Undervoltage");
break;
case 9:
sflag = "Vehicle is Running";
id(motor_system_flags).publish_state("Vehicle is Running");
break;
case 10:
sflag = "Traction is Enabled";
id(motor_system_flags).publish_state("Traction is Enabled");
break;
case 11:
sflag = "Hydraulic is Enabled";
id(motor_system_flags).publish_state("Hydraulic is Enabled");
break;
case 12:
sflag = "Powering is Enabled";
id(motor_system_flags).publish_state("Powering is Enabled");
break;
case 13:
sflag = "Powering is Ready";
id(motor_system_flags).publish_state("Powering is Ready");
break;
case 14:
sflag = "Powering is Precharging";
id(motor_system_flags).publish_state("Powering is Precharging");
break;
case 15:
sflag = "Main Contactor Closing";
id(motor_system_flags).publish_state("Main Contactor Closing");
break;
default:
sflag = "No System Flag";
break;
}
id(motor_system_flags).publish_state(sflag);
//Fault code
int fault_code = x[5];
id(motor_fault_code).publish_state(fault_code);
//Motor Temp
int temp = x[6] - 40;
id(motor_temp).publish_state(temp);
text_sensor:
- platform: template
id: motor_system_flags
name: "Motor System Flags"
- platform: template
id: motor_rpm
name: "Motor RPM"
sensor:
- platform: template
id: motor_battery_soc
name: "Motor Battery SoC"
accuracy_decimals: 0
- platform: template
id: motor_fault_code
name: "Motor Fault Code"
- platform: template
id: motor_temp
name: "Motor Temp"
accuracy_decimals: 0
Related
I am trying to compile a switch statement to create a combination lock of sorts from a nucleo board. At first I tried to tackle using multiple digital inputs in a switch statement by creating a bit mask and assigning integers, this seems to have gone alright however when I try to get my switch statement running it is stuck on case 0.
For a start case 0 should be no buttons pressed however it only activates once I press switch 1.
My second problem is that no other cases in my statement will activate at all.
I have no access to a debugger as mbed is not compatible with my nucleo board and I cannot get Keil Studio working so I am pretty stumped. Does anyone what is wrong with my statement or if there is an alternate way to refer to my digital inputs within the switch statement that may make it easier?
I am a coding n00b and have struggled to find much reference to my problem, any sample code I have looked at seems to work no problem and I cannot see where I have deviated from that code.
Code is below:
// You are to use these ojects to read the switch inputs
DigitalIn SW1(USER_BUTTON);
DigitalIn SW2(BTN1_PIN);
DigitalIn SW3(BTN2_PIN);
DigitalInOut SW4(BTN3_PIN, PIN_INPUT, PullDown, 0);
DigitalInOut SW5(BTN4_PIN, PIN_INPUT, PullDown, 0);
// You are to use this object to control the LEDs
BusOut leds(TRAF_RED1_PIN, TRAF_YEL1_PIN, TRAF_GRN1_PIN);
// Use this to sound an error
Buzzer alarm;
int main()
{
while (true)
{
leds = 0;
// Beep
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
// Wait for the blue button using a while loop
while (SW1==0) { };
// For full marks, debounce the switches with suitable delays
// This is a "combination lock" activity. Write some code to detect the following sequence of press-and-release inputs
// SW1, SW2, SW5, SW3 and SW4, SW2 and SW3
// If the full sequence is entered, correctly, the green LED should flash 3 times
// If a sequence of inputs was entered incorrectly, the red LED should light and the buzzer should sound for 5 seconds
// For full marks, debounce the switches and use flow control structures and arrays to avoid deep nesting of code
// ***** MODIFY THE CODE BELOW HERE *****
// ***** MODIFY THE CODE ABOVE HERE *****
int Inputs = (SW1==0) << 0 | (SW2==1) << 1 | (SW3==1) << 2 | (SW4==1) << 3 | (SW5==1) << 4;
int i;
switch (Inputs) {
case 0:
printf("Please Enter Combination\n");
if (false) {
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
leds = 4;
wait_us(5000000);
leds = 0;
}
break;
case 1:
printf("Input 1 is Correct\n");
if (false) {
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
leds = 4;
wait_us(5000000);
leds = 0;
}
break;
case 2:
printf("Input 2 is Correct\n");
if (false) {
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
leds = 4;
wait_us(5000000);
leds = 0;
}
break;
case 16:
printf("Input 3 is Correct\n");
if (false) {
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
leds = 4;
wait_us(5000000);
leds = 0;
}
break;
case 12:
printf("Input 4 is Correct\n");
if (false) {
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
leds = 4;
wait_us(5000000);
leds = 0;
}
break;
case 6:
printf("Combination is Correct!\n");
for (int i = 0; i < 3; i = i +1)
{
leds = 1;
wait_us(1000000);
leds = 0;
wait_us(1000000);
}
if (false) {
alarm.playTone("A", Buzzer::HIGHER_OCTAVE);
wait_us(250000);
alarm.rest();
leds = 4;
wait_us(5000000);
leds = 0;
}
You can make a bitmask integer where each bit corresponds to the state of one button like this:
unsigned int inputs = (SW1==0) << 0 | (SW2==0) << 1 | (SW3==0) << 2 | (SW4==0) << 3 | (SW5==0) << 4;
If you haven't seen those operators before, << is a left shift operator and | is a logical OR operator and you can look them up in any decent C++ book or introductory resource.
Your switch statement might look like this:
switch(inputs) {
case 0: // No buttons pressed
break;
case 1: // SW1 pressed (bit 0 is 1)
break;
case 2: // SW2 pressed (bit 1 is 1)
break;
case 4: // SW3 pressed (bit 2 is 1)
break;
case 6: // SW2 and SW3 pressed
break;
case 8: // SW4 pressed (bit 4 is 1)
break;
// ...
case 31: // All switches pressed
break;
}
I have a small script that defines the casting time for all classes in this minor project im working on however i have a few issues.
I want to place a cap on the max value however i'm getting errors!
this is the function i was referring to.
void Player::ApplyRatingMod(CombatRating combatRating, int32 value, bool apply)
{
float oldRating = m_baseRatingValue[combatRating];
m_baseRatingValue[combatRating] += (apply ? value : -value);
// explicit affected values
float const multiplier = GetRatingMultiplier(combatRating);
float const oldVal = oldRating * multiplier;
float const newVal = m_baseRatingValue[combatRating] * multiplier;
switch (combatRating)
{
case CR_HASTE_MELEE:
ApplyAttackTimePercentMod(BASE_ATTACK, oldVal, false);
ApplyAttackTimePercentMod(OFF_ATTACK, oldVal, false);
ApplyAttackTimePercentMod(BASE_ATTACK, newVal, true);
ApplyAttackTimePercentMod(OFF_ATTACK, newVal, true);
break;
case CR_HASTE_RANGED:
ApplyAttackTimePercentMod(RANGED_ATTACK, oldVal, false);
ApplyAttackTimePercentMod(RANGED_ATTACK, newVal, true);
break;
case CR_HASTE_SPELL:
//ApplyCastTimePercentMod(oldVal, false);
//ApplyCastTimePercentMod(newVal, true);
break;
default:
break;
}
UpdateRating(combatRating);
}
void Player::UpdateRating(CombatRating cr)
{
int32 amount = m_baseRatingValue[cr];
// Apply bonus from SPELL_AURA_MOD_RATING_FROM_STAT
// stat used stored in miscValueB for this aura
AuraEffectList const& modRatingFromStat = GetAuraEffectsByType(SPELL_AURA_MOD_RATING_FROM_STAT);
for (AuraEffect const* aurEff : modRatingFromStat)
if (aurEff->GetMiscValue() & (1 << cr))
amount += int32(CalculatePct(GetStat(Stats(aurEff->GetMiscValueB())), aurEff->GetAmount()));
if (amount < 0)
amount = 0;
SetUInt32Value(PLAYER_FIELD_COMBAT_RATING_1 + cr, uint32(amount));
bool affectStats = CanModifyStats();
switch (cr)
{
case CR_WEAPON_SKILL: // Implemented in Unit::RollMeleeOutcomeAgainst
case CR_DEFENSE_SKILL:
UpdateDefenseBonusesMod();
break;
case CR_DODGE:
UpdateDodgePercentage();
break;
case CR_PARRY:
UpdateParryPercentage();
break;
case CR_BLOCK:
UpdateBlockPercentage();
break;
case CR_HIT_MELEE:
UpdateMeleeHitChances();
break;
case CR_HIT_RANGED:
UpdateRangedHitChances();
break;
case CR_HIT_SPELL:
UpdateSpellHitChances();
break;
case CR_CRIT_MELEE:
if (affectStats)
{
UpdateCritPercentage(BASE_ATTACK);
UpdateCritPercentage(OFF_ATTACK);
}
break;
case CR_CRIT_RANGED:
if (affectStats)
UpdateCritPercentage(RANGED_ATTACK);
break;
case CR_CRIT_SPELL:
if (affectStats)
UpdateAllSpellCritChances();
break;
case CR_HIT_TAKEN_MELEE: // Implemented in Unit::MeleeMissChanceCalc
case CR_HIT_TAKEN_RANGED:
break;
case CR_HIT_TAKEN_SPELL: // Implemented in Unit::MagicSpellHitResult
break;
case CR_CRIT_TAKEN_MELEE: // Implemented in Unit::RollMeleeOutcomeAgainst (only for chance to crit)
case CR_CRIT_TAKEN_RANGED:
break;
case CR_CRIT_TAKEN_SPELL: // Implemented in Unit::SpellCriticalBonus (only for chance to crit)
break;
case CR_HASTE_MELEE: // Implemented in Player::ApplyRatingMod
case CR_HASTE_RANGED:
case CR_HASTE_SPELL:
break;
case CR_WEAPON_SKILL_MAINHAND: // Implemented in Unit::RollMeleeOutcomeAgainst
case CR_WEAPON_SKILL_OFFHAND:
case CR_WEAPON_SKILL_RANGED:
break;
case CR_EXPERTISE:
if (affectStats)
{
UpdateExpertise(BASE_ATTACK);
UpdateExpertise(OFF_ATTACK);
}
break;
case CR_ARMOR_PENETRATION:
if (affectStats)
UpdateArmorPenetration(amount);
break;
}
}
void Player::UpdateAllRatings()
{
for (uint8 cr = 0; cr < MAX_COMBAT_RATING; ++cr)
UpdateRating(CombatRating(cr));
}
You can notice how i want to cap the new value outcome to 32000.
Before it gets calculated to percentages!
I tried using
if(newVal > 32000)
newVal = 32000;
Which would normally do the job i guess, but i'm stuck with an error
E0137 expression must be a modifiable lvalue
On the line newVal = 32000;
Remove const qualifier from newVal
float newVal = m_baseRatingValue[combatRating] * multiplier;
You declare newVal as a constant (float const newVal = ...), so you're not allowed to assign a new value.
Removing const should work for you, e.g.
float newVal = m_baseRatingValue[combatRating] * multiplier;
if (newVal > 32000)
newVal = 32000;
...
I have the following enum (which later will grow larger!):
enum TrainingFilters {
NONE = 0,
GAUSS = 1,
SOBEL = 2,
FEATURE = 4
};
I have to print out string representation of the all possible combination. For now, a not-leangthy switch statement works fine, but if I add more items it will be disaster!
void Manager::setFilters(int filters)
{
QString what("Selected filters:");
switch (filters) {
case 0:
what.append(" NONE ");
break;
case 1:
what.append(" GAUSS ");
break;
case 1 | 2:
what.append(" GAUSS SOBEL ");
break;
case 2:
what.append(" SOBEL ");
break;
case 2 | 4:
what.append(" SOBEL FEATURE ");
break;
case 4:
what.append(" FEATURE ");
break;
case 1 | 4:
what.append(" GAUSS FEATURE ");
break;
case 1 | 2 | 4:
what.append(" GAUSS SOBEL FEATURE ");
break;
default:
qDebug() << "Invalid FILTERS enum received!";
return;
}
qDebug() << what;
mFilters = static_cast<TrainingFilters>(filters);
}
P.S: I have a few checkbox items in the user interface, and I should do some stuff according to the checked checkboxes. I use it like this:
var a, b,c;
cbGauss.checked ? a = 1 : a = 0;
cbSobel.checked ? b = 2 : b = 0;
cbFeat.checked ? c = 4 : c = 0;
cpManager.setFilters(a | b | c);
So my qustion is what is the best/easiest/smartest way to achieve this?
You could simply do
if (filters & 1)
what.append("GAUSS ");
if (filters & 2)
what.append("SOBEL ");
if (filters & 4)
what.append("FILTER ");
And so on. This way you can easily add new ones. Of course you have to check for zero and then add NONE.
I have something like this in fortran.
20: call TESTBEGIN(a,b,c)
if(c<1) goto 40
30: call TESTMIDDLE(e,f,g)
if(g==1) goto 20
40: return
But my code is like this
Subroutine testCase()
20: CALL beginTest(a,b)
IF (b.EQ.-1) GOTO 999
30: CALL middleTest(c,b)
IF (b.EQ.-1) GOTO 20
40: CALL endTest(d,b)
IF (b.EQ.-1) GOTO 30
CALL LastTest(e,b)
IF (.b.EQ.-1) GOTO 40
DO I =1,j
DTEMP(j)=1.0
END DO
some code
999:return
Something like that?
do
{
c = TESTBEGIN(a,b);
if (c < 1) break;
g = TESTMIDDLE(e,f);
} while ( g == 1 );
For the second code snippet try a state machine:
for(int state = 1; state != 0; )
{
switch(state)
{
case 1:
state = (beginTest(a) == -1) ? 0 : 2;
break;
case 2:
state = (middleTest(c) == -1) ? 1 : 3;
break;
case 3:
state = (endTest(d) == -1) ? 2 : 4;
break;
case 4:
state = (lastTest(e) == -1) ? 3 : 5;
break;
}
case 5:
state = 0;
// DO I =1,j // Honestly I don't know what does it do.
// DTEMP(j)=1.0
break;
}
Or better try to reconsider the algorithm, I think you could do it more easy to read and understand using Java.
I need to log information about how much RAM the user has. My first approach was to use GlobalMemoryStatusEx but that only gives me how much memory is available to windows, not how much is installed. I found this function GetPhysicallyInstalledSystemMemory but its only Vista and later. I need this to work on XP. Is there a fairly simple way of querying the SMBIOS information that GetPhysicallyInstalledSystemMemory was using or is there a registry value somewhere that I can find this out.
You should take a look at the Win32_ComputerSystem Class (WMI) and the TotalPhysicalMemory property. There are ways to access this information via .Net via the System.Management namespace for managed code (I use C#, so I haven't tried using visual studio for c++ development myself). You could also create a script to run WMI directly and have your c++ program call the script.
UPDATE: You may also look at the Win32_PhysicalMemory Class (take a look at the Capacity property). This will alleviate inaccurate readings due to the BIOS using some of the RAM etc.
UPDATE 2:
I've tried this in C# (3.5) and Windows XP (SP 2) and it works. I'm sure you can do something similar with the same WMI classes in C++ (at least through Visual Studio). It works no problem, so it's not a Vista or greater issue. I'm not sure if this is exactly what you are looking for, but this code will return the total physical memory capacity of the system (not how much is free). Hopefully this is what you meant. Anyway here is some sample code that locates each stick of RAM and displays some info about each one (including capacity) and then the total at the bottom:
using System;
using System.Collections.Generic;
using System.Management;
using System.Text;
namespace WmiTest
{
public class RamCounter
{
private List<RamStick> _ramSticks;
private int _totalRam;
private StringBuilder _stringRepresentation;
public RamCounter()
{
_ramSticks = new List<RamStick>();
_totalRam = 0;
_stringRepresentation = new StringBuilder();
}
public void GetRamSticks()
{
_ramSticks.Clear();
_totalRam = 0;
ManagementObjectSearcher searcher = new ManagementObjectSearcher("SELECT * FROM Win32_PhysicalMemory");
ManagementObjectCollection queryCollection = searcher.Get();
foreach (ManagementObject mo in queryCollection)
{
_ramSticks.Add(
new RamStick(Convert.ToUInt64(mo.GetPropertyValue("Capacity")),
mo.GetPropertyValue("DeviceLocator").ToString(),
mo.GetPropertyValue("Description").ToString(),
Convert.ToUInt32(mo.GetPropertyValue("FormFactor")),
Convert.ToUInt32(mo.GetPropertyValue("Speed"))));
}
}
public override string ToString()
{
_stringRepresentation.Capacity = 0;
foreach (RamStick rs in _ramSticks)
{
_stringRepresentation.Append(rs.ToString());
_totalRam += rs.CapacityInMB;
}
_stringRepresentation.Append("Total RAM(MB): " + _totalRam);
return _stringRepresentation.ToString();
}
}
public class RamStick
{
private UInt64 _capacity;
private UInt32 _formFactor;
public RamStick(UInt64 capacity, string location, string description, UInt32 formFactor, UInt32 speed)
{
_capacity = capacity;
Location = location;
Description = description;
_formFactor = formFactor;
Speed = speed;
}
public int CapacityInMB
{
get { return Convert.ToInt32(_capacity / (1024 * 1024)); }
}
public string Location
{
get;
private set;
}
public string Description
{
get;
private set;
}
public string GetFormFactor()
{
string formFactor = string.Empty;
switch (_formFactor)
{
case 1:
formFactor = "Other";
break;
case 2:
formFactor = "SIP";
break;
case 3:
formFactor = "DIP";
break;
case 4:
formFactor = "ZIP";
break;
case 5:
formFactor = "SOJ";
break;
case 6:
formFactor = "Proprietary";
break;
case 7:
formFactor = "SIMM";
break;
case 8:
formFactor = "DIMM";
break;
case 9:
formFactor = "TSOP";
break;
case 10:
formFactor = "PGA";
break;
case 11:
formFactor = "RIMM";
break;
case 12:
formFactor = "SODIMM";
break;
case 13:
formFactor = "SRIMM";
break;
case 14:
formFactor = "SMD";
break;
case 15:
formFactor = "SSMP";
break;
case 16:
formFactor = "QFP";
break;
case 17:
formFactor = "TQFP";
break;
case 18:
formFactor = "SOIC";
break;
case 19:
formFactor = "LCC";
break;
case 20:
formFactor = "PLCC";
break;
case 21:
formFactor = "BGA";
break;
case 22:
formFactor = "FPBGA";
break;
case 23:
formFactor = "LGA";
break;
default:
formFactor = "Unknown";
break;
}
return formFactor;
}
public UInt32 Speed
{
get;
private set;
}
public override string ToString()
{
return string.Format("Description:{1}{0}"
+ "Location:{2}{0}"
+ "Form Factor:{3}{0}"
+ "Speed:{4}{0}"
+ "Capacity(MB):{5}{0}{0}",
Environment.NewLine,
Description,
Location,
GetFormFactor(),
Speed,
CapacityInMB);
}
}
}
To use the code:
private void btnRam_Click(object sender, EventArgs e)
{
RamCounter rc = new RamCounter();
rc.GetRamSticks();
MessageBox.Show(rc.ToString());
}
Sample output from my machine:
Description: Physical Memory
Location: J6H1
Format Factor: DIMM
Speed: 667
Capacity(MB): 1024
Description: Physical Memory
Location: J6H2
Format Factor: DIMM
Speed: 667
Capacity(MB): 1024
Description: Physical Memory
Location: J6J1
Format Factor: DIMM
Speed: 667
Capacity(MB): 1024
Total RAM(MB): 3072
EDIT: I'd use steelbytes' answer, but if you can't use WMI For some reason, you can do this:
I don't believe Windows versions prior to Vista track this information -- you'd have to do some system specific BIOS or Motherboard enumeration to find the true value prior to Vista. Your best bet is to call the new API, GetPhysicallyInstalledSystemMemory, and fail over to GlobalMemoryStatusEx for XP systems.
I think WMI may give you this info ...
http://briandesmond.com/blog/getting-total-installed-memory-with-wmi/
One of the values returned by GlobalMemoryStatusEx is ullTotalPhys, which seems to be what you're looking for.
Things like ram used for video memory isn't in there, but I doubt there is a way to get to that at all.