Bologna
Offline
Newbie
Karma: 0
Posts: 42
L'anima sta all'uomo come l'uomo sta alla macchina
|
 |
« on: August 29, 2012, 05:08:25 am » |
consider this snippet, compiled with Arduino IDE: PROGMEM char charSet[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF }; char reversed[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF }; char ff; for (int i=0; i < 16; i++) { Serial.print(" "); Serial.print(reversed[i], HEX); } Serial.println(" "); for (int i=0; i < 16; i++) { Serial.print(" "); ff = pgm_read_byte(&charSet[i]); Serial.print(ff); } I would expect the two for loops to produce same output. But the output is: 0 8 4 C 2 A 6 E 1 9 5 D 3 B 7 F FFFFFF94 FFFFFFB0 6 FFFFFF80 FFFFFF91 FFFFFFC7 3 62 FFFFFFE3 E FFFFFF94 5E 29 FFFFFF99 23 39 What am I missing? Thank you
|
|
|
|
|
Logged
|
twitter: @shineangelic
|
|
|
|
North Queensland, Australia
Offline
Edison Member
Karma: 35
Posts: 1279
|
 |
« Reply #1 on: August 29, 2012, 05:48:41 am » |
try a different declaration char charSet[] PROGMEM = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF }; also try below instead of assigning to ff Serial.print( pgm_read_byte( charSet + i ) );
|
|
|
|
|
Logged
|
|
|
|
|
0
Offline
Tesla Member
Karma: 76
Posts: 6849
Arduino rocks
|
 |
« Reply #2 on: August 29, 2012, 05:53:09 am » |
The AVR microcontrollers are Harvard architecture - code and data are in separate memories (flash and SRAM respectively).
|
|
|
|
|
Logged
|
|
|
|
|
Leeds, UK
Offline
Newbie
Karma: 0
Posts: 29
|
 |
« Reply #3 on: August 29, 2012, 06:05:40 am » |
Surely you want Serial.print(ff, HEX); rather than just Serial.print(ff); if you want the output to look the same.
Having said that, it looks like serial.print is assuming you have passed a long rather than a char, which I don't understand yet.
Paul
|
|
|
|
|
Logged
|
|
|
|
|
Bologna
Offline
Newbie
Karma: 0
Posts: 42
L'anima sta all'uomo come l'uomo sta alla macchina
|
 |
« Reply #4 on: August 29, 2012, 06:56:10 am » |
Surely you want Serial.print(ff, HEX); rather than just Serial.print(ff); if you want the output to look the same. Yes, you're right. Anyway the output is the same. Also Serial.print( pgm_read_byte( charSet + i ), HEX ); produces same output. I really can't understand
|
|
|
|
|
Logged
|
twitter: @shineangelic
|
|
|
|
New Hampshire
Offline
God Member
Karma: 13
Posts: 776
There are 10 kinds of people, those who know binary, and those who don't.
|
 |
« Reply #5 on: August 29, 2012, 06:58:24 am » |
Having said that, it looks like serial.print is assuming you have passed a long rather than a char, which I don't understand yet.
All of the various print(type, base) overloads are piping through print(long, base) apparently to avoid code duplication. The unfortunate side effect is that Hex values print with too many leading Fs.
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
UK
Online
Brattain Member
Karma: 143
Posts: 19366
I don't think you connected the grounds, Dave.
|
 |
« Reply #6 on: August 29, 2012, 07:07:31 am » |
The unfortunate side effect is that Hex values print with too many leading Fs. Only if you're using signed datatypes.
|
|
|
|
|
Logged
|
Pete, it's a fool looks for logic in the chambers of the human heart.
|
|
|
|
Leeds, UK
Offline
Newbie
Karma: 0
Posts: 29
|
 |
« Reply #7 on: August 29, 2012, 07:09:59 am » |
So ff should be an unsigned char as in? unsigned char ff; Paul
|
|
|
|
|
Logged
|
|
|
|
|
Global Moderator
UK
Online
Brattain Member
Karma: 143
Posts: 19366
I don't think you connected the grounds, Dave.
|
 |
« Reply #8 on: August 29, 2012, 07:11:46 am » |
Or "byte", as in " pgm_read_byte"
|
|
|
|
|
Logged
|
Pete, it's a fool looks for logic in the chambers of the human heart.
|
|
|
|
Bologna
Offline
Newbie
Karma: 0
Posts: 42
L'anima sta all'uomo come l'uomo sta alla macchina
|
 |
« Reply #9 on: August 29, 2012, 02:48:01 pm » |
I'v tried with unsigned char and byte, but no luck. The output is: 0 8 4 C 2 A 6 E 1 9 5 D 3 B 7 F 91 C8 3 A8 16 B9 6 CA 6 DB 6 A1 F0 E 94 D3 The code I'm using is: byte charSet[] PROGMEM = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF }; byte reversed[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF }; byte ff; for (int i=0; i < 16; i++) { Serial.print(" "); Serial.print(reversed[i], HEX); } Serial.println(" "); for (int i=0; i < 16; i++) { Serial.print(" "); ff = pgm_read_byte(&charSet[i]); Serial.print(ff, HEX); }
|
|
|
|
|
Logged
|
twitter: @shineangelic
|
|
|
|
Offline
Edison Member
Karma: 16
Posts: 1036
Arduino rocks
|
 |
« Reply #10 on: August 29, 2012, 02:56:38 pm » |
const byte charSet[] PROGMEM = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF }; byte reversed[] = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF };
void setup() { Serial.begin(115200);
byte ff; for (int i=0; i < 16; i++) { Serial.print(" "); Serial.print(reversed[i], HEX); } Serial.println(" "); for (int i=0; i < 16; i++) { Serial.print(" "); ff = pgm_read_byte(&charSet[i]); Serial.print(ff, HEX); } }
void loop() {
}
returns 0 8 4 C 2 A 6 E 1 9 5 D 3 B 7 F 0 8 4 C 2 A 6 E 1 9 5 D 3 B 7 F on my computer/arduino. $ avr-gcc -v Using built-in specs. COLLECT_GCC=avr-gcc COLLECT_LTO_WRAPPER=/usr/lib/gcc/avr/4.7.1/lto-wrapper Target: avr Configured with: /build/src/gcc-4.7.1/configure --prefix=/usr --libdir=/usr/lib --libexecdir=/usr/lib --mandir=/usr/share/man --infodir=/usr/share/info --enable-languages=c,c++ --disable-libssp --disable-nls --target=avr --with-as=/usr/bin/avr-as --with-ld=/usr/bin/avr-ld --with-gnu-as --with-gnu-ld Thread model: single gcc version 4.7.1 (GCC)
$ pacman -Qi avr-libc Name : avr-libc Version : 1.8.0-4 URL : http://savannah.nongnu.org/projects/avr-libc/ Licenses : BSD Groups : None Provides : None Depends On : avr-gcc Optional Deps : None Required By : None Conflicts With : None Replaces : None Installed Size : 23684.00 KiB Packager : schuay <jakob.gruber@gmail.com> Architecture : any Build Date : Sun Jun 24 01:12:18 2012 Install Date : Thu Jun 28 08:33:48 2012 Install Reason : Explicitly installed Install Script : No Description : The C runtime library for the AVR family of microcontrollers
arduino uno r2
|
|
|
|
|
Logged
|
|
|
|
|
Bologna
Offline
Newbie
Karma: 0
Posts: 42
L'anima sta all'uomo come l'uomo sta alla macchina
|
 |
« Reply #11 on: August 29, 2012, 03:08:41 pm » |
thank you. I had to add const keyword and to move the declaration outside the function.
Now it works.
|
|
|
|
|
Logged
|
twitter: @shineangelic
|
|
|
|
Global Moderator
UK
Online
Brattain Member
Karma: 143
Posts: 19366
I don't think you connected the grounds, Dave.
|
 |
« Reply #12 on: August 29, 2012, 03:10:20 pm » |
That's why we prefer it that you DON'T post code snippets
|
|
|
|
|
Logged
|
Pete, it's a fool looks for logic in the chambers of the human heart.
|
|
|
|
Bologna
Offline
Newbie
Karma: 0
Posts: 42
L'anima sta all'uomo come l'uomo sta alla macchina
|
 |
« Reply #13 on: August 29, 2012, 03:23:11 pm » |
The snippet is part of a rudimental Air conditioner IR driver, I thought it was too long to be posted for a simple issue. I'll post it, so maybe someone will find other inconsistencies in my rusty C code. It works, but I'd like to decrease memory usage furthermore. Thanks to anyone who'll be looking at it. #include <avr/pgmspace.h> //These are Samsung MH026FB specific #define tempmask 0xF//temp e` quarto byte dell'input #define funmask 0xF0 #define fanmask 0x700 #define swirlmask 0x800
#include "IRremoteInt_light.h" #include "IRremote_light.h"
const byte charSet[] PROGMEM = { 0x0, 0x8, 0x4, 0xc, 0x2, 0xA , 0x6, 0xE, 0x1, 0x9,0x5, 0xD, 0x3,0xB,0x7,0xF }; #define DEBUG 1 /** Souliss Aircon MH026FB Driver implements IR logic. Commanded by Souliss AirCon protocol SAMSUNG MH026 series */ //IR_Remote lite library IRsend irsend; /** Counts number of 1 in a long */ int NumberOfSetBits(long i) { i = i - ((i >> 1) & 0x55555555); i = (i & 0x33333333) + ((i >> 2) & 0x33333333); return (((i + (i >> 4)) & 0x0F0F0F0F) * 0x01010101) >> 24; } /** Reverse the bit in a byte via a lookup table Bit reversal lookup table 0100 --> 0010 //TODO use progmem */ char revbits(int n) {
return pgm_read_byte(&charSet[n]); //return reversed[n]; } /** Compute Samsung crappy checksum Command is split between data and data2 Samsung checksum 1. Count the number of 1 bits in all the bytes except #2 (checksum) 2. Compute count mod 15. If the value is 0, use 15 instead. 3. Take the value from 2, flip the 4 bits, and reverse the 4 bits. 4. The checksum is Bn where n is the value from the previous step.
Note that step 2 is mod 15, not mod 16 (which you might expect). I don't know why 15 is used as a special case instead of 0.
For step 3, the results in order are F, 7, B, 3, D, 5, 9, 1, E, 6, A, 2, C, 4, 8, 0. Note that these are exactly the same as the values you got for byte 5 (temperature). This suggests that the reversed / inverted bits are more "fundamental". Thanks to Ken Shirriff */ long computeChecksum(long data, long data2){ char temp; temp = NumberOfSetBits(data2); temp +=NumberOfSetBits(data); temp = temp%15; if (temp == 0) temp = 15; #ifdef DEBUG Serial.print("NUMBITS SET:"); Serial.println(temp, HEX); #endif temp = ~temp; temp -=0xF0; #ifdef DEBUG Serial.print("INVERTED:"); Serial.println(temp, HEX); Serial.print("REVERSED:"); Serial.println(revbits(temp), HEX); #endif return 0xB0 + revbits(temp); }
/************************************************************************** /*! Remap Souliss AirCon data with device specific one (Samsung MH026FB). You'll have to re-implement this function to support your Air Conditioner. Souliss INPUT Data is: 0xABCD A = 4 bit mask (XYZT X= powerON, Y PowerOFF, ionizer (airclean) , pwrsave) B = Fan/Swirl (1bit switch + 3bits for four possible fan values) C = Function (auto,cool,dry,fan,heat) D = Temperature (from 16 to 30, see .h) I comandi sono formati da due o tre burst --------------------------------------------------------------- OUTPUT (Samsung specific) Codice dati da inviare: 7F XX 80 71 F 1 7 7 F0 const check swirl const ion tem fan fun const DEFAULT 00000000 00000000 00000000 01110001 0000 0000 0000 0000 00000000
*/ /**************************************************************************/ void sendMH026FB(unsigned long data, U8 *memory_map, U8 slot){
long part1=0; long part2=0;
#ifdef DEBUG Serial.print("Souliss AirCon input:"); Serial.println(data, HEX); #endif if (data & 0x8000){//if first bit of input=0 TURN ON #ifdef DEBUG Serial.println("POWERON!"); #endif irsend.sendSamsung(0xBFB20FFF, 0xFFFFF0); irsend.sendSamsung(0x7FB40FFF, 0xFFFFFF); //*status = Souliss_T_IrCom_AirCon_Pow_On; //go on with command } else if (data<<1 & 0x8000) {//if second bit of input=0 SHUT OFF #ifdef DEBUG Serial.println("POWEROFF!"); #endif irsend.sendSamsung(0xBFB20FFF, 0xFFFFFC); irsend.sendSamsung(0x7FB40FFF, 0xFFFFFF); irsend.sendSamsung(0x7FB08A71, 0xF84FFC); //*status = Souliss_T_IrCom_AirCon_Pow_Off;
//memory_map[MaCaco_OUT_s + slot] = *status; //memory_map[MaCaco_OUT_s + slot + 1] = *status; memory_map[MaCaco_IN_s + slot] = Souliss_T_IrCom_AirCon_Reset; return; } else {//Comando da due bursts, primo costante irsend.sendSamsung(0xBFB20FFFUL ,0xFFFFF0UL ); } //starting values part1 = 0x7f000000; part2 = 0x0000F0; //last part1 const (andrebbe 11 -> turbo) e 01->Powersave unsigned int powerMode = Souliss_T_IrCom_AirCon_opt_normal; //FAN is bit 2,3,4 of 2nd BYTE of INPUT char fan = (data & fanmask)>>8; //FUN = 3rd byte of INPUT char fun = (data & funmask)>>4;
//TEMP = 4th byte of INPUT long temperat = data & tempmask; //swirl OFF by default unsigned int swirl = 0x80; //swirl (if deflector has to swing) if (data & swirlmask){ swirl=0x8A; } //Eco bit Toggle, only in cool mode if ((data<<3 & 0x8000) && (fun == Souliss_T_IrCom_AirCon_Fun_Cool)) powerMode = Souliss_T_IrCom_AirCon_opt_eco; //PART2 //OPT if terzo bit = 1 IONIZER if (data<<2 & 0x8000) part2 += 0x700000;//Ion ON else part2 += 0xF00000;//F = Ion OFF //Fan has only 24 degrees if (fun == Souliss_T_IrCom_AirCon_Fun_Fan) temperat = Souliss_T_IrCom_AirCon_temp_24C; //Dry has only AUTO fan setting if (fun == Souliss_T_IrCom_AirCon_Fun_Dry) fan = Souliss_T_IrCom_AirCon_Fan_Auto; //Auto mode adjust: fan and options are fixed if (fun == Souliss_T_IrCom_AirCon_Fun_Auto){ fan = 0x4; //swirl=0x8A; powerMode = Souliss_T_IrCom_AirCon_opt_normal; } part1 += swirl<<8; part1 += powerMode; //temperature on sixth byte part2 += temperat<<16; part2 += fan<<12; part2 += fun<<8; //has to be last call part1 += computeChecksum(part1, part2)<<16; //send command irsend.sendSamsung(part1, part2); #ifdef DEBUG Serial.print("Sending 0x"); Serial.print(part1, HEX); Serial.print(" "); Serial.println(part2, HEX); #endif //*status = data; }
|
|
|
|
|
Logged
|
twitter: @shineangelic
|
|
|
|
|