int bit_file::alloc_read_data(FILE* f) { unsigned int i; // Read length if (fread(&length, 4, 1, f) != 1) return -1; length = NTOH32(length); data = (u8*)malloc(length); if (data == NULL) return -1; if (fread(data, 1, length, f) != length) { clear(); return -1; } // Reverse bytes for (i = 0; i < length; i++) data[i] = reverse8(data[i]); return 0; }
uint16_t reverse16(uint16_t value) { uint16_t reversed; reversed = reverse8(value >> 8); reversed |= reverse8(value & 0xFF) << 8; return reversed; }
cs_status cs_plat_ssp_serdes_read( CS_IN cs_callback_context_t context, CS_IN cs_dev_id_t device, CS_IN cs_llid_t llidport, CS_IN cs_uint8 offset, CS_OUT cs_uint8 *data ) { cs_status ret = CS_E_OK; cs_uint8 raddr_rev; cs_uint32 read_data; if(NULL == data){ return CS_E_PARAM; } raddr_rev = reverse8(offset); cs_plat_ssp_transaction_begin(context,device,llidport,SSP_SLAVE_ID_3); /* set clock at 8.9MHz */ ret = cs_plat_ssp_init_cfg_set(context,device,llidport, SSP_SLAVE_ID_3,8900,SSP_STANDARD_SPI,SSP_TDAT_CPHA_CENTER, SSP_IDAT_MODE_CENTER,SSP_DATIN_CMD_PHASE,SSP_DATA_CENTER_ALIGN); if(CS_E_OK == ret){ ret = cs_plat_ssp_frame_cfg_set(context,device,llidport, SSP_SLAVE_ID_3,0x7,0x9,SSP_NORMAL); } else{ cs3_deselect(); cs_plat_ssp_transaction_end(context,device,llidport,SSP_SLAVE_ID_3); return ret; } ret = cs_plat_ssp_read(context,device,llidport,SSP_SLAVE_ID_3, (0x01<<30 | raddr_rev<<22),0,0,&read_data); *data = reverse8(read_data & 0x000000ff); cs3_deselect(); cs_plat_ssp_transaction_end(context,device,llidport,SSP_SLAVE_ID_3); return ret; }
cs_status cs_plat_ssp_serdes_write( CS_IN cs_callback_context_t context, CS_IN cs_dev_id_t device, CS_IN cs_llid_t llidport, CS_IN cs_uint8 offset, CS_IN cs_uint8 data ) { cs_status ret = CS_E_OK; cs_uint8 waddr_rev = reverse8(offset); cs_uint8 wdata_rev = reverse8(data); cs_plat_ssp_transaction_begin(context,device,llidport,SSP_SLAVE_ID_3); /* set clock at 8.9MHz */ ret = cs_plat_ssp_init_cfg_set(context,device,llidport, SSP_SLAVE_ID_3,8900,SSP_STANDARD_SPI,SSP_TDAT_CPHA_CENTER, SSP_IDAT_MODE_CENTER,SSP_DATIN_DATA_PHASE,SSP_DATA_CENTER_ALIGN); if(CS_E_OK == ret){ ret = cs_plat_ssp_frame_cfg_set(context,device,llidport, SSP_SLAVE_ID_3,0x7,0x9,SSP_NORMAL); } else{ cs3_deselect(); cs_plat_ssp_transaction_end(context,device,llidport,SSP_SLAVE_ID_3); return ret; } ret = cs_plat_ssp_write(context,device,llidport,SSP_SLAVE_ID_3, (waddr_rev<<22),0,0,wdata_rev); cs3_deselect(); cs_plat_ssp_transaction_end(context,device,llidport,SSP_SLAVE_ID_3); return ret; }
uint16_t crc16(const uint8_t *buf, size_t len, uint16_t pol, uint16_t remainder, bool reverse_in) { for (int i = 0; i < len; i++) { if (reverse_in) { remainder ^= (reverse8(buf[i]) << 8); } else { remainder ^= buf[i] << 8; } for (uint8_t bit = 8; bit > 0; --bit) { if (remainder & 0x8000) { remainder = (remainder << 1) ^ pol; } else { remainder = (remainder << 1); } } // for } return remainder; }
static void basic_tests(void) { #if 0 // test basic PWM functionality, put a 2MHz 33% dutycycle sqwave out TCCR1 = _BV(PWM1A) | _BV(COM1A0) | _BV(CS10); GTCCR = 0; OCR1C = 3; OCR1A = 1; while(1) { ; } #endif #if 0 // test based IR frequency output IRsend_enableIROut(); IRsend_iron(); while( 1 ) { ; } #endif #if 0 // test basic IR sending capability while( 1 ) { IRsend_sendSony( 0x610, 12); // 7 key //IRsend_sendSony( 0x910, 12); // 0 key _delay_ms(1500); IRsend_sendSony( 0xa90, 12); // power key _delay_ms(1500); } #endif #if 0 // test basic IR sending capability int c = 0; while( 1 ) { IRsend_sendSony( c, 16); _delay_ms(50); c--; } #endif #if 0 // test basic IR sending capability while( 1 ) { IRsend_sendRC5( TOPBIT + 0x1234, 32); // _delay_ms(1500); IRsend_sendRC5( TOPBIT + 0xABCD, 32); // _delay_ms(1500); } #endif #if 0 // test basic IR sending capability int c = 0; while( 1 ) { IRsend_sendRC6( c, 32); // _delay_ms(50); c--; } #endif #if 0 // test basic IR sending capability int c = 0; while( 1 ) { IRsend_txByte( reverse8(c) ); // _delay_ms(50); c++; } #endif #if 0 // test basic IR sending capability int c = 0; while( 1 ) { IRsend_sendSonyData4( c ); // c += 0x100; //c--; //_delay_ms(50); // 50msec needed when using IRrecvDump _delay_ms(5); // 3msec GAP in ctrlm source IRsend_sendSonyData4( c ); // c++; //c--; /* _delay_ms(5); IRsend_sendSonyData4( c-- ); // _delay_ms(5); IRsend_sendSonyData4( c-- ); // */ _delay_ms(100); } #endif #if 1 // test basic IR sending capability uint8_t b[8] = {0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF}; // uint64_t* dp = (uint64_t*) b; while( 1 ) { IRsend_sendSonyData64bit( b ); // //c += 0x1; //c--; b[0]++; b[7]++; _delay_ms(20); } #endif }
// Parse the user data for captions. The udtype variable denotes // to which type of data it belongs: // 0 .. sequence header // 1 .. GOP header // 2 .. picture header // Return TRUE if the data parsing finished, FALSE otherwise. // estream->pos is advanced. Data is only processed if ustream->error // is FALSE, parsing can set ustream->error to TRUE. int user_data(struct lib_cc_decode *ctx, struct bitstream *ustream, int udtype, struct cc_subtitle *sub) { dbg_print(CCX_DMT_VERBOSE, "user_data(%d)\n", udtype); // Shall not happen if (ustream->error || ustream->bitsleft <= 0) { // ustream->error=1; return 0; // Actually discarded on call. // CFS: Seen in a Wobble edited file. // fatal(CCX_COMMON_EXIT_BUG_BUG, "user_data: Impossible!"); } // Do something ctx->stat_numuserheaders++; //header+=4; unsigned char *ud_header = next_bytes(ustream, 4); if (ustream->error || ustream->bitsleft <= 0) { return 0; // Actually discarded on call. // CFS: Seen in Stick_VHS.mpg. // fatal(CCX_COMMON_EXIT_BUG_BUG, "user_data: Impossible!"); } // DVD CC header, see // <http://www.theneitherworld.com/mcpoodle/SCC_TOOLS/DOCS/SCC_FORMAT.HTML> if ( !memcmp(ud_header,"\x43\x43", 2 ) ) { ctx->stat_dvdccheaders++; // Probably unneeded, but keep looking for extra caption blocks int maybeextracb = 1; read_bytes(ustream, 4); // "43 43 01 F8" unsigned char pattern_flag = (unsigned char) read_bits(ustream,1); read_bits(ustream,1); int capcount=(int) read_bits(ustream,5); int truncate_flag = (int) read_bits(ustream,1); // truncate_flag - one CB extra int field1packet = 0; // expect Field 1 first if (pattern_flag == 0x00) field1packet=1; // expect Field 1 second dbg_print(CCX_DMT_VERBOSE, "Reading %d%s DVD CC segments\n", capcount, (truncate_flag?"+1":"")); capcount += truncate_flag; // This data comes before the first frame header, so // in order to get the correct timing we need to set the // current time to one frame after the maximum time of the // last GOP. Only useful when there are frames before // the GOP. if (ctx->timing->fts_max > 0) ctx->timing->fts_now = ctx->timing->fts_max + (LLONG) (1000.0/current_fps); int rcbcount = 0; for (int i=0; i<capcount; i++) { for (int j=0;j<2;j++) { unsigned char data[3]; data[0]=read_u8(ustream); data[1]=read_u8(ustream); data[2]=read_u8(ustream); // Obey the truncate flag. if ( truncate_flag && i == capcount-1 && j == 1 ) { maybeextracb = 0; break; } /* Field 1 and 2 data can be in either order, with marker bytes of \xff and \xfe Since markers can be repeated, use pattern as well */ if ((data[0]&0xFE) == 0xFE) // Check if valid { if (data[0]==0xff && j==field1packet) data[0]=0x04; // Field 1 else data[0]=0x05; // Field 2 do_cb(ctx, data, sub); rcbcount++; } else { dbg_print(CCX_DMT_VERBOSE, "Illegal caption segment - stop here.\n"); maybeextracb = 0; break; } } } // Theoretically this should not happen, oh well ... // Deal with extra closed captions some DVD have. int ecbcount = 0; while ( maybeextracb && (next_u8(ustream)&0xFE) == 0xFE ) { for (int j=0;j<2;j++) { unsigned char data[3]; data[0]=read_u8(ustream); data[1]=read_u8(ustream); data[2]=read_u8(ustream); /* Field 1 and 2 data can be in either order, with marker bytes of \xff and \xfe Since markers can be repeated, use pattern as well */ if ((data[0]&0xFE) == 0xFE) // Check if valid { if (data[0]==0xff && j==field1packet) data[0]=0x04; // Field 1 else data[0]=0x05; // Field 2 do_cb(ctx, data, sub); ecbcount++; } else { dbg_print(CCX_DMT_VERBOSE, "Illegal (extra) caption segment - stop here.\n"); maybeextracb = 0; break; } } } dbg_print(CCX_DMT_VERBOSE, "Read %d/%d DVD CC blocks\n", rcbcount, ecbcount); } // SCTE 20 user data else if (!ctx->noscte20 && ud_header[0] == 0x03) { if ((ud_header[1]&0x7F) == 0x01) { unsigned char cc_data[3*31+1]; // Maximum cc_count is 31 ctx->stat_scte20ccheaders++; read_bytes(ustream, 2); // "03 01" unsigned cc_count = (unsigned int) read_bits(ustream,5); dbg_print(CCX_DMT_VERBOSE, "Reading %d SCTE 20 CC blocks\n", cc_count); unsigned field_number; unsigned cc_data1; unsigned cc_data2; for (unsigned j=0;j<cc_count;j++) { skip_bits(ustream,2); // priority - unused field_number = (unsigned int) read_bits(ustream,2); skip_bits(ustream,5); // line_offset - unused cc_data1 = (unsigned int) read_bits(ustream,8); cc_data2 = (unsigned int) read_bits(ustream,8); read_bits(ustream,1); // TODO: Add syntax check */ if (ustream->bitsleft < 0) fatal(CCX_COMMON_EXIT_BUG_BUG, "In user_data: ustream->bitsleft < 0. Cannot continue."); // Field_number is either // 0 .. forbidden // 1 .. field 1 (odd) // 2 .. field 2 (even) // 3 .. repeated, from repeat_first_field, effectively field 1 if (field_number < 1) { // 0 is invalid cc_data[j*3]=0x00; // Set to invalid cc_data[j*3+1]=0x00; cc_data[j*3+2]=0x00; } else { // Treat field_number 3 as 1 field_number = (field_number - 1) & 0x01; // top_field_first also affects to which field the caption // belongs. if(!ctx->top_field_first) field_number ^= 0x01; cc_data[j*3]=0x04|(field_number); cc_data[j*3+1]=reverse8(cc_data1); cc_data[j*3+2]=reverse8(cc_data2); } } cc_data[cc_count*3]=0xFF; store_hdcc(ctx, cc_data, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub); dbg_print(CCX_DMT_VERBOSE, "Reading SCTE 20 CC blocks - done\n"); } // reserved - unspecified } // ReplayTV 4000/5000 caption header - parsing information // derived from CCExtract.bdl else if ( (ud_header[0] == 0xbb //ReplayTV 4000 || ud_header[0] == 0x99) //ReplayTV 5000 && ud_header[1] == 0x02 ) { unsigned char data[3]; if (ud_header[0]==0xbb) ctx->stat_replay4000headers++; else ctx->stat_replay5000headers++; read_bytes(ustream, 2); // "BB 02" or "99 02" data[0]=0x05; // Field 2 data[1]=read_u8(ustream); data[2]=read_u8(ustream); do_cb(ctx, data, sub); read_bytes(ustream, 2); // Skip "CC 02" for R4000 or "AA 02" for R5000 data[0]=0x04; // Field 1 data[1]=read_u8(ustream); data[2]=read_u8(ustream); do_cb(ctx, data, sub); } // HDTV - see A/53 Part 4 (Video) else if ( !memcmp(ud_header,"\x47\x41\x39\x34", 4 ) ) { ctx->stat_hdtv++; read_bytes(ustream, 4); // "47 41 39 34" unsigned char type_code = read_u8(ustream); if (type_code==0x03) // CC data. { skip_bits(ustream,1); // reserved unsigned char process_cc_data = (unsigned char) read_bits(ustream,1); skip_bits(ustream,1); // additional_data - unused unsigned char cc_count = (unsigned char) read_bits(ustream,5); read_bytes(ustream, 1); // "FF" if (process_cc_data) { dbg_print(CCX_DMT_VERBOSE, "Reading %d HDTV CC blocks\n", cc_count); int proceed = 1; unsigned char *cc_data = read_bytes(ustream, cc_count*3); if (ustream->bitsleft < 0) fatal(CCX_COMMON_EXIT_BUG_BUG, "In user_data: ustream->bitsleft < 0. Cannot continue.\n"); // Check for proper marker - This read makes sure that // cc_count*3+1 bytes are read and available in cc_data. if (read_u8(ustream)!=0xFF) proceed=0; if (!proceed) { dbg_print(CCX_DMT_VERBOSE, "\rThe following payload is not properly terminated.\n"); dump (CCX_DMT_VERBOSE, cc_data, cc_count*3+1, 0, 0); } dbg_print(CCX_DMT_VERBOSE, "Reading %d HD CC blocks\n", cc_count); // B-frames might be (temporal) before or after the anchor // frame they belong to. Store the buffer until the next anchor // frame occurs. The buffer will be flushed (sorted) in the // picture header (or GOP) section when the next anchor occurs. // Please note we store the current value of the global // fts_now variable (and not get_fts()) as we are going to // re-create the timeline in process_hdcc() (Slightly ugly). store_hdcc(ctx, cc_data, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub); dbg_print(CCX_DMT_VERBOSE, "Reading HDTV blocks - done\n"); } } // reserved - additional_cc_data } // DVB closed caption header for Dish Network (Field 1 only) */ else if ( !memcmp(ud_header,"\x05\x02", 2 ) ) { // Like HDTV (above) Dish Network captions can be stored at each // frame, but maximal two caption blocks per frame and only one // field is stored. // To process this with the HDTV framework we create a "HDTV" caption // format compatible array. Two times 3 bytes plus one for the 0xFF // marker at the end. Pre-init to field 1 and set the 0xFF marker. static unsigned char dishdata[7] = {0x04, 0, 0, 0x04, 0, 0, 0xFF}; int cc_count; dbg_print(CCX_DMT_VERBOSE, "Reading Dish Network user data\n"); ctx->stat_dishheaders++; read_bytes(ustream, 2); // "05 02" // The next bytes are like this: // header[2] : ID: 0x04 (MPEG?), 0x03 (H264?) // header[3-4]: Two byte counter (counting (sub-)GOPs?) // header[5-6]: Two bytes, maybe checksum? // header[7]: Pattern type // on B-frame: 0x02, 0x04 // on I-/P-frame: 0x05 unsigned char id = read_u8(ustream); unsigned dishcount = read_u16(ustream); unsigned something = read_u16(ustream); unsigned char type = read_u8(ustream); dbg_print(CCX_DMT_PARSE, "DN ID: %02X Count: %5u Unknown: %04X Pattern: %X", id, dishcount, something, type); unsigned char hi; // The following block needs 4 to 6 bytes starting from the // current position unsigned char *dcd = ustream->pos; // dish caption data switch (type) { case 0x02: // Two byte caption - always on B-frame // The following 4 bytes are: // 0 : 0x09 // 1-2: caption block // 3 : REPEAT - 02: two bytes // - 04: four bytes (repeat first two) dbg_print(CCX_DMT_PARSE, "\n02 %02X %02X:%02X - R:%02X :", dcd[0], dcd[1], dcd[2], dcd[3]); cc_count = 1; dishdata[1]=dcd[1]; dishdata[2]=dcd[2]; dbg_print(CCX_DMT_PARSE, "%s", debug_608_to_ASC( dishdata, 0) ); type=dcd[3]; // repeater (0x02 or 0x04) hi = dishdata[1] & 0x7f; // Get only the 7 low bits if (type==0x04 && hi<32) // repeat (only for non-character pairs) { cc_count = 2; dishdata[3]=0x04; // Field 1 dishdata[4]=dishdata[1]; dishdata[5]=dishdata[2]; dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608_to_ASC( dishdata+3, 0) ); } else { dbg_print(CCX_DMT_PARSE, ":\n"); } dishdata[cc_count*3] = 0xFF; // Set end marker store_hdcc(ctx, dishdata, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub); // Ignore 3 (0x0A, followed by two unknown) bytes. break; case 0x04: // Four byte caption - always on B-frame // The following 5 bytes are: // 0 : 0x09 // 1-2: caption block // 3-4: caption block dbg_print(CCX_DMT_PARSE, "\n04 %02X %02X:%02X:%02X:%02X :", dcd[0], dcd[1], dcd[2], dcd[3], dcd[4]); cc_count = 2; dishdata[1]=dcd[1]; dishdata[2]=dcd[2]; dishdata[3]=0x04; // Field 1 dishdata[4]=dcd[3]; dishdata[5]=dcd[4]; dishdata[6] = 0xFF; // Set end marker dbg_print(CCX_DMT_PARSE, "%s", debug_608_to_ASC( dishdata, 0) ); dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608_to_ASC( dishdata+3, 0) ); store_hdcc(ctx, dishdata, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub); // Ignore 4 (0x020A, followed by two unknown) bytes. break; case 0x05: // Buffered caption - always on I-/P-frame // The following six bytes are: // 0 : 0x04 // - the following are from previous 0x05 caption header - // 1 : prev dcd[2] // 2-3: prev dcd[3-4] // 4-5: prev dcd[5-6] dbg_print(CCX_DMT_PARSE, " - %02X pch: %02X %5u %02X:%02X\n", dcd[0], dcd[1], (unsigned)dcd[2]*256+dcd[3], dcd[4], dcd[5]); dcd+=6; // Skip these 6 bytes // Now one of the "regular" 0x02 or 0x04 captions follows dbg_print(CCX_DMT_PARSE, "%02X %02X %02X:%02X", dcd[0], dcd[1], dcd[2], dcd[3]); type=dcd[0]; // Number of caption bytes (0x02 or 0x04) cc_count = 1; dishdata[1]=dcd[2]; dishdata[2]=dcd[3]; dcd+=4; // Skip the first 4 bytes. if (type==0x02) { type=dcd[0]; // repeater (0x02 or 0x04) dcd++; // Skip the repeater byte. dbg_print(CCX_DMT_PARSE, " - R:%02X :%s", type, debug_608_to_ASC( dishdata, 0) ); hi = dishdata[1] & 0x7f; // Get only the 7 low bits if (type==0x04 && hi<32) { cc_count = 2; dishdata[3]=0x04; // Field 1 dishdata[4]=dishdata[1]; dishdata[5]=dishdata[2]; dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608_to_ASC( dishdata+3, 0) ); } else { dbg_print(CCX_DMT_PARSE, ":\n"); } dishdata[cc_count*3] = 0xFF; // Set end marker } else { dbg_print(CCX_DMT_PARSE, ":%02X:%02X ", dcd[0], dcd[1]); cc_count = 2; dishdata[3]=0x04; // Field 1 dishdata[4]=dcd[0]; dishdata[5]=dcd[1]; dishdata[6] = 0xFF; // Set end marker dbg_print(CCX_DMT_PARSE, ":%s", debug_608_to_ASC( dishdata, 0) ); dbg_print(CCX_DMT_PARSE, "%s:\n", debug_608_to_ASC( dishdata+3, 0) ); } store_hdcc(ctx, dishdata, cc_count, ctx->timing->current_tref, ctx->timing->fts_now, sub); // Ignore 3 (0x0A, followed by 2 unknown) bytes. break; default: // printf ("Unknown?\n"); break; } // switch dbg_print(CCX_DMT_VERBOSE, "Reading Dish Network user data - done\n"); } // CEA 608 / aka "Divicom standard", see: // http://www.pixeltools.com/tech_tip_closed_captioning.html else if ( !memcmp(ud_header,"\x02\x09", 2 ) ) { // Either a documentation or more examples are needed. ctx->stat_divicom++; unsigned char data[3]; read_bytes(ustream, 2); // "02 09" read_bytes(ustream, 2); // "80 80" ??? read_bytes(ustream, 2); // "02 0A" ??? data[0]=0x04; // Field 1 data[1]=read_u8(ustream); data[2]=read_u8(ustream); do_cb(ctx, data, sub); // This is probably incomplete! } // GXF vbi OEM code else if ( !memcmp(ud_header,"\x73\x52\x21\x06", 4 ) ) { int udatalen = ustream->end - ustream->pos; uint16_t line_nb; uint8_t line_type; uint8_t field = 1; read_bytes(ustream, 4); //skip header code read_bytes(ustream, 2); //skip data length line_nb = read_bits(ustream, 16); line_type = read_u8(ustream); field = (line_type & 0x03); if(field == 0) mprint("MPEG:VBI: Invalid field\n"); line_type = line_type >> 2; if(line_type != 1) mprint("MPEG:VBI: only support Luma line\n"); if (udatalen < 720) mprint("MPEG:VBI: Minimum 720 bytes in luma line required\n"); decode_vbi(ctx, field, ustream->pos, 720, sub); dbg_print(CCX_DMT_VERBOSE, "GXF (vbi line %d) user data:\n", line_nb); }
static int acurite_986_callback(bitbuffer_t *bitbuf) { int browlen; uint8_t *bb, sensor_num, status, crc, crcc; uint8_t br[8]; int8_t tempf; // Raw Temp is 8 bit signed Fahrenheit float tempc; uint16_t sensor_id, valid_cnt = 0; char sensor_type; local_time_str(0, time_str); if (debug_output > 1) { fprintf(stderr,"acurite_986\n"); bitbuffer_print(bitbuf); } for (uint16_t brow = 0; brow < bitbuf->num_rows; ++brow) { browlen = (bitbuf->bits_per_row[brow] + 7)/8; bb = bitbuf->bb[brow]; if (debug_output > 1) fprintf(stderr,"acurite_986: row %d bits %d, bytes %d \n", brow, bitbuf->bits_per_row[brow], browlen); if (bitbuf->bits_per_row[brow] < 39 || bitbuf->bits_per_row[brow] > 43 ) { if (debug_output > 1 && bitbuf->bits_per_row[brow] > 16) fprintf(stderr,"acurite_986: skipping wrong len\n"); continue; } // Reduce false positives // may eliminate these with a beter PPM (precise?) demod. if ((bb[0] == 0xff && bb[1] == 0xff && bb[2] == 0xff) || (bb[0] == 0x00 && bb[1] == 0x00 && bb[2] == 0x00)) { continue; } // There will be 1 extra false zero bit added by the demod. // this forces an extra zero byte to be added if (browlen > 5 && bb[browlen - 1] == 0) browlen--; // Reverse the bits for (uint8_t i = 0; i < browlen; i++) br[i] = reverse8(bb[i]); if (debug_output > 0) { fprintf(stderr,"Acurite 986 reversed: "); for (uint8_t i = 0; i < browlen; i++) fprintf(stderr," %02x",br[i]); fprintf(stderr,"\n"); } tempf = br[0]; sensor_id = (br[1] << 8) + br[2]; status = br[3]; sensor_num = (status & 0x01) + 1; status = status >> 1; // By default Sensor 1 is the Freezer, 2 Refrigerator sensor_type = sensor_num == 2 ? 'F' : 'R'; crc = br[4]; if ((crcc = crc8le(br, 5, 0x07, 0)) != 0) { // XXX make debug if (debug_output) { fprintf(stderr,"%s Acurite 986 sensor bad CRC: %02x -", time_str, crc8le(br, 4, 0x07, 0)); for (uint8_t i = 0; i < browlen; i++) fprintf(stderr," %02x", br[i]); fprintf(stderr,"\n"); } continue; } if ((status & 1) == 1) { fprintf(stderr, "%s Acurite 986 sensor 0x%04x - %d%c: low battery, status %02x\n", time_str, sensor_id, sensor_num, sensor_type, status); } // catch any status bits that haven't been decoded yet if ((status & 0xFE) != 0) { fprintf(stderr, "%s Acurite 986 sensor 0x%04x - %d%c: Unexpected status %02x\n", time_str, sensor_id, sensor_num, sensor_type, status); } if (tempf & 0x80) { tempf = (tempf & 0x7f) * -1; } tempc = fahrenheit2celsius(tempf); printf("%s Acurite 986 sensor 0x%04x - %d%c: %3.1f C %d F\n", time_str, sensor_id, sensor_num, sensor_type, tempc, tempf); valid_cnt++; } if (valid_cnt) return 1; return 0; }
/// @param *data : returns the decoded information as a data_t * static int decode_xc0324_message(r_device *decoder, bitbuffer_t *bitbuffer, unsigned row, uint16_t bitpos, const int latest_event, data_t **data) { uint8_t b[XC0324_MESSAGE_BYTELEN]; char id [4] = {0}; double temperature; uint8_t flags; uint8_t chksum; // == 0x00 for a good message // Extract the message bitbuffer_extract_bytes(bitbuffer, row, bitpos, b, XC0324_MESSAGE_BITLEN); // Examine the chksum and bail out now if not OK to save time // b[5] is a check byte, the XOR of bytes 0-4. // ie a checksum where the sum is "binary add no carry" // Effectively, each bit of b[5] is the parity of the bits in the // corresponding position of b[0] to b[4] // NB : b[0] ^ b[1] ^ b[2] ^ b[3] ^ b[4] ^ b[5] == 0x00 for a clean message chksum = xor_bytes(b, 6); if (chksum != 0x00) { if (decoder->verbose == 1) { // Output the "bad" message (only for message level deciphering!) decoder_output_bitrowf(decoder, b, XC0324_MESSAGE_BITLEN, "chksum = 0x%02X not 0x00 <- XC0324:vv row %d bit %d", chksum, row, bitpos); } return 0; // No message was able to be decoded } // Extract the id as hex string snprintf(id, 3, "%02X", b[1]); // Decode temperature (b[2]), plus 1st 4 bits b[3], LSB first order! // Tenths of degrees C, offset from the minimum possible (-40.0 degrees) uint16_t temp = ((uint16_t)(reverse8(b[3]) & 0x0f) << 8) | reverse8(b[2]) ; temperature = (temp / 10.0) - 40.0 ; //Unknown byte, constant as 0x80 in all my data // ??maybe battery status?? flags = b[4]; // Create the data structure, ready for the decoder_output_data function. // Separate production output (decoder->verbose == 0) // from (simulated) deciphering stage output (decoder->verbose > 0) if (!decoder->verbose) { // production output *data = data_make( "model", "Device Type", DATA_STRING, "Digitech XC0324", "id", "ID", DATA_STRING, id, "temperature_C", "Temperature C", DATA_FORMAT, "%.1f", DATA_DOUBLE, temperature, "flags", "Constant ?", DATA_INT, flags, "mic", "Integrity", DATA_STRING, "CHECKSUM", NULL); } // Output (simulated) message level deciphering information.. if (decoder->verbose == 1) { decoder_output_bitrowf(decoder, b, XC0324_MESSAGE_BITLEN, "Temp was %4.1f <- XC0324:vv row %03d bit %03d", temperature, row, bitpos); } // Output "finished deciphering" reference values for future regression tests. if ((decoder->verbose == 3) & (latest_event == 0)) { //info from this first successful message is enough decoder_output_messagef(decoder, "XC0324:vvvv Reference -> Temperature %4.1f C; sensor id %s", temperature, id); } return 1; // Message successfully decoded }