boolean WebServer::begin (NetworkInterface& _netint, const Page* const _pages[] #ifdef ENABLE_TAGS , const ReplacementTag* const _substitutions[] #endif #if defined (WEBBINO_ENABLE_SD) || defined (WEBBINO_ENABLE_SDFAT) , int8_t pin #endif ) { boolean ret = true; netint = &_netint; pages = _pages; #ifndef WEBBINO_NDEBUG DPRINTLN (F("Pages available in flash memory:")); const Page *p = NULL; for (byte i = 0; pages && (p = reinterpret_cast<const Page *> (pgm_read_ptr (&pages[i]))); i++) { DPRINT (i); DPRINT (F(". ")); DPRINTLN (PSTR_TO_F (p -> getName ())); } #endif #ifdef ENABLE_TAGS substitutions = _substitutions; #ifndef WEBBINO_NDEBUG DPRINTLN (F("Tags available:")); const ReplacementTag* sub; for (byte i = 0; substitutions && (sub = reinterpret_cast<const ReplacementTag *> (pgm_read_ptr (&substitutions[i]))); i++) { DPRINT (i); DPRINT (F(". ")); DPRINTLN (PSTR_TO_F (sub -> getName ())); } #endif #endif #if defined (WEBBINO_ENABLE_SD) || defined (WEBBINO_ENABLE_SDFAT) if (pin >= 0) { DPRINT (F("Initializing SD card...")); if (!SD.begin (pin)) { DPRINTLN (F(" failed")); ret = false; } DPRINTLN (F(" done")); } #endif return ret; }
EventHandlerResult MagicCombo::beforeReportingState() { for (byte i = 0; i < magiccombo::combos_length; i++) { bool match = true; byte j; for (j = 0; j < MAX_COMBO_LENGTH; j++) { int8_t comboKey = pgm_read_byte(&(magiccombo::combos[i].keys[j])); if (comboKey == 0) break; match &= KeyboardHardware.isKeyswitchPressed(comboKey); if (!match) break; } if (j != KeyboardHardware.pressedKeyswitchCount()) match = false; if (match && (millis() >= end_time_)) { ComboAction action = (ComboAction) pgm_read_ptr(&(magiccombo::combos[i].action)); (*action)(i); end_time_ = millis() + min_interval; } } return EventHandlerResult::OK; }
static inline void sleepNow() { // All LEDs off for(int i = 0; i < LED_COUNT; i++) { *((unsigned char *)pgm_read_ptr(&(LED_PORT[i]))) &= ~_BV(pgm_read_byte(&(LED_PIN[i]))); } // We want to do this carefully. If someone pushes the button // while we're prepareing here, we do NOT want to 'eat' that // interrupt. Rather, we want to enable interrupts at the same // time we call sleep_cpu() (sei() is defferred for one instruction). // That way the button push will effectively cancel the sleep rather // than get 'eaten'. ATOMIC_BLOCK(ATOMIC_FORCEON) { power_timer0_disable(); PCMSK0 |= _BV(PCINT5); GIMSK |= _BV(PCIE0); sleep_enable(); } sleep_cpu(); // And now we wake up sleep_disable(); PCMSK0 &= ~_BV(PCINT5); GIMSK &= ~_BV(PCIE0); power_timer0_enable(); button_debounce_time = millis(); ignoring_button = 1; place_in_pattern = -1; milli_of_next_change = 0; }
const Page* WebServer::getPage (const char* name) const { const Page *p = NULL; // For some reason, if we make i a byte here, the code uses 8 more bytes, so don't! for (unsigned int i = 0; pages && (p = reinterpret_cast<const Page *> (pgm_read_ptr (&pages[i]))); i++) { if (strcmp_P (name, p -> getName ()) == 0) break; } return p; }
/** Retrieves a pointer to the value of the given Attribute ID from the given Attribute table. * * \param[in] ServiceEntry Pointer to the service entry whose attribute table is to be examined * \param[in] AttributeID Attribute ID to search for within the table * * \return Pointer to the start of the Attribute's value if found within the table, NULL otherwise */ static void* SDP_GetAttributeValue(const SDP_ServiceEntry_t* const ServiceEntry, const uint16_t AttributeID) { /* Search through the current Attribute table, abort when the terminator item has been reached */ for (uint8_t i = 0; i < ServiceEntry->TotalTableAttributes; i++) { /* Check if the current Attribute ID matches the search ID - if so return a pointer to it */ if (pgm_read_word(&ServiceEntry->AttributeTable[i].AttributeID) == AttributeID) return pgm_read_ptr(&ServiceEntry->AttributeTable[i].Data); } return NULL; }
PString* WebServer::findSubstitutionTag (const char *tag) const { const ReplacementTag *sub; PString* ret = NULL; for (byte i = 0; !ret && (sub = reinterpret_cast<const ReplacementTag *> (pgm_read_ptr (&substitutions[i]))); i++) { if (strcmp_P (tag, sub -> getName ()) == 0) { PString& pb = (sub -> getFunction ()) (sub -> getData ()); ret = &pb; } } return ret; }
inline void exec_slice(void) { int8_t i; void (*slot_ptr)(void); for(i=0; i<NUMBER_OF_ITEMS_PER_SLOT; i++) { slot_ptr = pgm_read_ptr(&g_sched_list[g_next_slice][i]); if (slot_ptr != NULL) { g_next_item = i; (*slot_ptr)(); clock_in(); } } }
/** Retrieves a pointer to the value of the given Attribute ID from the given Attribute table. * * \param[in] AttributeTable Pointer to the Attribute table to search in * \param[in] AttributeID Attribute ID to search for within the table * * \return Pointer to the start of the Attribute's value if found within the table, NULL otherwise */ static void* SDP_GetAttributeValue(const ServiceAttributeTable_t* AttributeTable, const uint16_t AttributeID) { void* CurrTableItemData; /* Search through the current Attribute table, abort when the terminator item has been reached */ while ((CurrTableItemData = pgm_read_ptr(&AttributeTable->Data)) != NULL) { /* Check if the current Attribute ID matches the search ID - if so return a pointer to it */ if (pgm_read_word(&AttributeTable->AttributeID) == AttributeID) return CurrTableItemData; AttributeTable++; } return NULL; }
/** Adds all the Attributes in the given service table to the response that appear in the Attribute table. * * \param[in] AttributeTable Pointer to an Attribute table for the service to examine * \param[in] AttributeList Pointer to a list of Attribute ranges * \param[in] TotalAttributes Number of Attributes stored in the Attribute list * \param[out] BufferPos Pointer to the output buffer position where the retrieved attributes are to be stored * * \return Number of bytes added to the output buffer */ static uint16_t SDP_AddListedAttributesToResponse(const ServiceAttributeTable_t* AttributeTable, uint16_t AttributeList[][2], const uint8_t TotalAttributes, void** const BufferPos) { uint16_t TotalResponseSize; /* Add an inner Data Element Sequence header for the current services's found Attributes */ uint16_t* AttributeListSize = SDP_AddSequence16(BufferPos); /* Search through the list of Attributes one at a time looking for values in the current UUID's Attribute table */ for (uint8_t CurrAttribute = 0; CurrAttribute < TotalAttributes; CurrAttribute++) { uint16_t* AttributeIDRange = AttributeList[CurrAttribute]; void* AttributeValue; /* Look through the current service's attribute list, examining all the attributes */ while ((AttributeValue = pgm_read_ptr(&AttributeTable->Data)) != NULL) { /* Get the current Attribute's ID from the current attribute table entry */ uint16_t CurrAttributeID = pgm_read_word(&AttributeTable->AttributeID); /* Check if the current Attribute's ID is within the current Attribute range */ if ((CurrAttributeID >= AttributeIDRange[0]) && (CurrAttributeID <= AttributeIDRange[1])) { /* Increment the current UUID's returned Attribute container size by the number of added bytes */ *AttributeListSize += SDP_AddAttributeToResponse(CurrAttributeID, AttributeValue, BufferPos); } AttributeTable++; } } /* Record the total number of added bytes to the buffer */ TotalResponseSize = 3 + *AttributeListSize; /* Fix endianness of the added attribute data element sequence */ *AttributeListSize = SwapEndian_16(*AttributeListSize); return TotalResponseSize; }
/** Retrieves the Attribute table for the given UUID list if it exists. * * \param[in] ServiceEntry Pointer to the service entry whose attribute table is to be examined * \param[in] UUIDList List of UUIDs which must be matched within the service attribute table * \param[in] TotalUUIDs Total number of UUIDs stored in the UUID list * * \return True if all the UUIDs given in the UUID list appear in the given attribute table, false otherwise */ static bool SDP_SearchServiceTable(const SDP_ServiceEntry_t* const ServiceEntry, uint8_t UUIDList[][UUID_SIZE_BYTES], const uint8_t TotalUUIDs) { uint16_t UUIDMatchFlags = 0; /* Search through the current attribute table, checking each attribute value for UUID matches */\ for (uint8_t i = 0; i < ServiceEntry->TotalTableAttributes; i++) { const void* CurrAttribute = pgm_read_ptr(&ServiceEntry->AttributeTable[i].Data); SDP_CheckUUIDMatch(UUIDList, TotalUUIDs, &UUIDMatchFlags, CurrAttribute); } /* Determine how many UUID matches in the list we have found */ uint8_t UUIDMatches; for (UUIDMatches = 0; UUIDMatchFlags; UUIDMatches++) UUIDMatchFlags &= (UUIDMatchFlags - 1); /* If all UUIDs have been matched to the current service, return true */ return (UUIDMatches == TotalUUIDs); }
/** Retrieves the Attribute table for the given UUID list if it exists. * * \param[in] UUIDList List of UUIDs which must be matched within the service attribute table * \param[in] TotalUUIDs Total number of UUIDs stored in the UUID list * \param[in] CurrAttributeTable Pointer to the service attribute table to search through * * \return True if all the UUIDs given in the UUID list appear in the given attribute table, false otherwise */ static bool SDP_SearchServiceTable(uint8_t UUIDList[][UUID_SIZE_BYTES], const uint8_t TotalUUIDs, const ServiceAttributeTable_t* CurrAttributeTable) { const void* CurrAttribute; uint16_t UUIDMatchFlags = 0; /* Search through the current attribute table, checking each attribute value for UUID matches */ while ((CurrAttribute = pgm_read_ptr(&CurrAttributeTable->Data)) != NULL) { SDP_CheckUUIDMatch(UUIDList, TotalUUIDs, &UUIDMatchFlags, CurrAttribute); CurrAttributeTable++; } /* Determine how many UUID matches in the list we have found */ uint8_t UUIDMatches; for (UUIDMatches = 0; UUIDMatchFlags; UUIDMatches++) UUIDMatchFlags &= (UUIDMatchFlags - 1); /* If all UUIDs have been matched to the current service, return true */ return (UUIDMatches == TotalUUIDs); }
void loop() { while(1) { // Do this about once a minute-ish. if (q_random() % 30 != 0) { // a normal second. doTick(); for(int i = 0; i < IRQS_PER_SECOND - 1; i++) doSleep(); continue; } // Time to play a song! unsigned int song = q_random() % SONG_COUNT; unsigned char *current_song = (unsigned char*)pgm_read_ptr(song_table + song); while(1) { unsigned char song_data = pgm_read_byte(current_song++); if (song_data == 0) break; // song over doTick(); for(int i = 0; i < song_data; i++) doSleep(); } } }
void main() { // power management setup clock_prescale_set(clock_div_16); // 500 kHz clock ADCSRA = 0; // DIE, ADC! DIE!!! power_adc_disable(); power_usi_disable(); power_timer1_disable(); ACSR = _BV(ACD); set_sleep_mode(SLEEP_MODE_PWR_DOWN); // millisecond timer setup TCCR0A = _BV(WGM01); // mode 2 - CTC TCCR0B = _BV(CS01) | _BV(CS00); // prescale = 64 TIMSK0 = _BV(OCIE0A); // OCR0A interrupt only. OCR0A = IRQ_CYCLE_LENGTH + 1; millis_counter = 0; irq_cycle_pos = 0; sei(); // I/O port setup DDRA = _BV(PA0) | _BV(PA1) | _BV(PA2) | _BV(PA3) | _BV(PA7); DDRB = _BV(PB0) | _BV(PB1) | _BV(PB2); PORTA = _BV(PA5); // enable the pull-up on the button pin PORTB = 0; unsigned char pattern = eeprom_read_byte(EE_PATTERN_NUM); if (pattern >= PATTERN_COUNT) pattern = 0; place_in_pattern = -1; milli_of_next_change = 0; button_debounce_time = 0; button_press_time = 0; ignoring_button = 0; while(1) { unsigned long now = millis(); // poll for button events unsigned int event = checkEvent(); switch(event) { case EVENT_LONG_PUSH: sleepNow(); continue; case EVENT_SHORT_PUSH: if (++pattern >= PATTERN_COUNT) pattern = 0; place_in_pattern = -1; milli_of_next_change = 0; eeprom_write_byte(EE_PATTERN_NUM, pattern); continue; } // If it's time to move to the next step in a pattern, pull out its // mask and clear all of the LEDs. // Note that now > milli_of_next_change is wrong here because our // time wraps. now - milli_of_next_change > 0 *looks* the same, // but handles cases where the sign differs. if (milli_of_next_change == 0 || ((long)(now - milli_of_next_change)) >= 0) { // It's time to go to the next step in the pattern place_in_pattern++; const struct pattern_entry *our_pattern = (struct pattern_entry *)pgm_read_ptr(&(patterns[pattern])); struct pattern_entry entry; do { memcpy_P(&entry, (void*)(&(our_pattern[place_in_pattern])), sizeof(struct pattern_entry)); // A duration of 0 is the end of the pattern. if (entry.duration != 0) break; place_in_pattern = 0; } while(1); // This means a pattern of a single entry with 0 duration is kryptonite. current_mask = entry.mask; // Turn out all the lights for(int i = 0; i < LED_COUNT; i++) { *((unsigned char *)pgm_read_ptr(&(LED_PORT[i]))) &= ~_BV(pgm_read_byte(&(LED_PIN[i]))); } milli_of_next_change = now + entry.duration; current_led = 99; //invalid } // Now multiplex the LEDSs. Rotate through all of the set bits in the // current mask and turn the next one on every pass through this loop. if (current_mask != 0) { // if it IS zero, then all the lights are out anyway. unsigned char next_led = current_led; while(1) { // we know it's not zero, so there's at least one bit set if (++next_led >= LED_COUNT) next_led = 0; if (current_mask & (1 << next_led)) break; // found one! } if (next_led != current_led) { // turn the old one off and the new one on. if (current_led < LED_COUNT) // is it safe? *((unsigned char *)pgm_read_ptr(&(LED_PORT[current_led]))) &= ~_BV(pgm_read_byte(&(LED_PIN[current_led]))); *((unsigned char *)pgm_read_ptr(&(LED_PORT[next_led]))) |= _BV(pgm_read_byte(&(LED_PIN[next_led]))); current_led = next_led; } } } }
LOOP_L_N(f, COUNT(custom_bootscreen_animation)) { if (f) safe_delay(CUSTOM_BOOTSCREEN_FRAME_TIME); draw_custom_bootscreen((u8g_pgm_uint8_t*)pgm_read_ptr(&custom_bootscreen_animation[f]), f == 0); }
// // This loads a default setting from the table for the given index // int MenloDweet::LoadDefaultSettingFromTable( struct StateSettingsParameters* parms, int index ) { #if DWEET_STATE_ENABLE_DEFAULT_TABLE_SUPPORT int configDataIndex; int configDataLength; int defaultDataIndex; int defaultTableIndex; char* defaultDataPtr; int retVal; if (parms->defaultsTable == NULL) { return 0; } // Get the configuration data index and length for the entry configDataIndex = pgm_read_word(&parms->indexTable[index]); configDataLength = pgm_read_word(&parms->sizeTable[index]); // // Lookup the data index in the defaults table and see if an entry // has been provided. // // The defaults table is not in order to allow it to be sparse since // not all values need an automatic default setting. // for (defaultTableIndex = 0;; defaultTableIndex++) { defaultDataIndex = pgm_read_word((const int*)(&parms->defaultsTable[defaultTableIndex].configIndex)); if (defaultDataIndex == 0) { // No entry found in defaultsTable return 0; } if (defaultDataIndex == index) { break; } } defaultDataPtr = (char*)pgm_read_ptr((const int*)(&parms->defaultsTable[defaultTableIndex].address)); // Get the config data from the default data pointer memcpy(&parms->workingBuffer[0], defaultDataPtr, configDataLength); ConfigStore.ProcessConfigBufferForValidChars(&parms->workingBuffer[0], configDataLength); parms->workingBuffer[configDataLength] = '\0'; // Now try and set it on the object using the SETSTATE function retVal = MenloDweet::DispatchFunctionFromTable( parms->functionTable, parms->object, index, parms->workingBuffer, configDataLength, true ); return retVal; #else return 0; #endif }
/** Internal processing routine for SDP Service Attribute Requests. * * \param[in] SDPHeader Pointer to the start of the issued SDP request * \param[in] Channel Pointer to the Bluetooth channel structure the request was issued to */ static void SDP_ProcessServiceAttribute(const SDP_PDUHeader_t* const SDPHeader, Bluetooth_Channel_t* const Channel) { const void* CurrentParameter = ((const void*)SDPHeader + sizeof(SDP_PDUHeader_t)); BT_SDP_DEBUG(1, "<< Service Attribute"); /* Retrieve the service handle whose attributes are to be examined */ uint32_t ServiceHandle = SDP_ReadData32(&CurrentParameter); BT_SDP_DEBUG(2, "-- Service Handle: 0x%08lX", ServiceHandle); /* Retrieve the maximum Attribute response size from the request */ uint16_t MaxAttributeSize = SDP_ReadData16(&CurrentParameter); BT_SDP_DEBUG(2, "-- Max Return Attribute Bytes: 0x%04X", MaxAttributeSize); /* Retrieve the list of Attributes from the request */ uint16_t AttributeList[8][2]; uint8_t TotalAttributes = SDP_GetAttributeList(AttributeList, &CurrentParameter); BT_SDP_DEBUG(2, "-- Total Attributes: %d", TotalAttributes); struct { SDP_PDUHeader_t SDPHeader; uint16_t AttributeListByteCount; uint8_t ResponseData[100]; } ResponsePacket; /* Create a pointer to the buffer to indicate the current location for response data to be added */ void* CurrResponsePos = ResponsePacket.ResponseData; /* Clamp the maximum attribute size to the size of the allocated buffer */ if (MaxAttributeSize > sizeof(ResponsePacket.ResponseData)) MaxAttributeSize = sizeof(ResponsePacket.ResponseData); uint16_t TotalResponseSize = 0; /* Search through the global UUID list an item at a time */ for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++) { /* Read in a pointer to the current UUID table entry's Attribute table */ ServiceAttributeTable_t* CurrAttributeTable = pgm_read_ptr(&SDP_Services_Table[CurrTableItem]); /* Retrieve a PROGMEM pointer to the value of the Service Record Handle */ const void* ServiceRecord = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE); /* Get the size of the header for the Service Record Handle */ uint8_t AttrHeaderSize; SDP_GetLocalAttributeContainerSize(ServiceRecord, &AttrHeaderSize); /* Retrieve the endian-swapped service handle of the current service being examined */ uint32_t CurrServiceHandle = SwapEndian_32(pgm_read_dword(ServiceRecord + AttrHeaderSize)); /* Check if the current service in the service table has the requested service handle */ if (ServiceHandle == CurrServiceHandle) { /* Add the listed attributes for the found UUID to the response */ TotalResponseSize = SDP_AddListedAttributesToResponse(CurrAttributeTable, AttributeList, TotalAttributes, &CurrResponsePos); /* Requested service found, abort the search through the service table */ break; } } /* Continuation state - always zero */ SDP_WriteData8(&CurrResponsePos, 0); /* Set the total response list size to the size of the outer container plus its header size and continuation state */ ResponsePacket.AttributeListByteCount = SwapEndian_16(TotalResponseSize); /* Calculate the total parameter length that is to be sent, including the fixed return parameters, the created attribute value list and the SDP continuation state */ uint16_t ParamLength = (sizeof(ResponsePacket.AttributeListByteCount) + TotalResponseSize + sizeof(uint8_t)); /* Fill in the response packet's header */ ResponsePacket.SDPHeader.PDU = SDP_PDU_SERVICEATTRIBUTERESPONSE; ResponsePacket.SDPHeader.TransactionID = SDPHeader->TransactionID; ResponsePacket.SDPHeader.ParameterLength = SwapEndian_16(ParamLength); BT_SDP_DEBUG(1, ">> Service Attribute Response"); BT_SDP_DEBUG(2, "-- Param Len 0x%04X", ParamLength); /* Send the completed response packet to the sender */ Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket.SDPHeader) + ParamLength), Channel); }
/** Internal processing routine for SDP Service Search Attribute Requests. * * \param[in] SDPHeader Pointer to the start of the issued SDP request * \param[in] Channel Pointer to the Bluetooth channel structure the request was issued to */ static void SDP_ProcessServiceSearchAttribute(const SDP_PDUHeader_t* const SDPHeader, Bluetooth_Channel_t* const Channel) { const void* CurrentParameter = ((const void*)SDPHeader + sizeof(SDP_PDUHeader_t)); BT_SDP_DEBUG(1, "<< Service Search Attribute"); /* Retrieve the list of search UUIDs from the request */ uint8_t UUIDList[12][UUID_SIZE_BYTES]; uint8_t TotalUUIDs = SDP_GetUUIDList(UUIDList, &CurrentParameter); BT_SDP_DEBUG(2, "-- Total UUIDs: %d", TotalUUIDs); /* Retrieve the maximum Attribute response size from the request */ uint16_t MaxAttributeSize = SDP_ReadData16(&CurrentParameter); BT_SDP_DEBUG(2, "-- Max Return Attribute Bytes: 0x%04X", MaxAttributeSize); /* Retrieve the list of Attributes from the request */ uint16_t AttributeList[8][2]; uint8_t TotalAttributes = SDP_GetAttributeList(AttributeList, &CurrentParameter); BT_SDP_DEBUG(2, "-- Total Attributes: %d", TotalAttributes); struct { SDP_PDUHeader_t SDPHeader; uint16_t AttributeListByteCount; uint8_t ResponseData[100]; } ResponsePacket; /* Create a pointer to the buffer to indicate the current location for response data to be added */ void* CurrResponsePos = ResponsePacket.ResponseData; /* Clamp the maximum attribute size to the size of the allocated buffer */ if (MaxAttributeSize > sizeof(ResponsePacket.ResponseData)) MaxAttributeSize = sizeof(ResponsePacket.ResponseData); /* Add the outer Data Element Sequence header for all of the retrieved Attributes */ uint16_t* TotalResponseSize = SDP_AddSequence16(&CurrResponsePos); /* Search through the global service list an item at a time */ for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++) { /* Read in a pointer to the current UUID table entry's Attribute table */ ServiceAttributeTable_t* CurrAttributeTable = pgm_read_ptr(&SDP_Services_Table[CurrTableItem]); if (!(SDP_SearchServiceTable(UUIDList, TotalUUIDs, CurrAttributeTable))) continue; BT_SDP_DEBUG(2, " -- Found search match in table"); /* Add the listed attributes for the found UUID to the response */ *TotalResponseSize += SDP_AddListedAttributesToResponse(CurrAttributeTable, AttributeList, TotalAttributes, &CurrResponsePos); } /* Continuation state - always zero */ SDP_WriteData8(&CurrResponsePos, 0); /* Set the total response list size to the size of the outer container plus its header size and continuation state */ ResponsePacket.AttributeListByteCount = SwapEndian_16(3 + *TotalResponseSize); /* Calculate the total parameter length that is to be sent, including the fixed return parameters, the created attribute value list and the SDP continuation state */ uint16_t ParamLength = (sizeof(ResponsePacket.AttributeListByteCount) + (3 + *TotalResponseSize) + sizeof(uint8_t)); /* Flip the endianness of the container's size */ *TotalResponseSize = SwapEndian_16(*TotalResponseSize); /* Fill in the response packet's header */ ResponsePacket.SDPHeader.PDU = SDP_PDU_SERVICESEARCHATTRIBUTERESPONSE; ResponsePacket.SDPHeader.TransactionID = SDPHeader->TransactionID; ResponsePacket.SDPHeader.ParameterLength = SwapEndian_16(ParamLength); BT_SDP_DEBUG(1, ">> Service Search Attribute Response"); BT_SDP_DEBUG(2, "-- Param Len 0x%04X", ParamLength); /* Send the completed response packet to the sender */ Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket.SDPHeader) + ParamLength), Channel); }
inline const __FlashStringHelper* FF(const char* const* s) { return reinterpret_cast<const __FlashStringHelper*>( pgm_read_ptr(s)); }
/** Internal processing routine for SDP Service Search Requests. * * \param[in] SDPHeader Pointer to the start of the issued SDP request * \param[in] Channel Pointer to the Bluetooth channel structure the request was issued to */ static void SDP_ProcessServiceSearch(const SDP_PDUHeader_t* const SDPHeader, Bluetooth_Channel_t* const Channel) { const void* CurrentParameter = ((const void*)SDPHeader + sizeof(SDP_PDUHeader_t)); BT_SDP_DEBUG(1, "<< Service Search"); /* Retrieve the list of search UUIDs from the request */ uint8_t UUIDList[12][UUID_SIZE_BYTES]; uint8_t TotalUUIDs = SDP_GetUUIDList(UUIDList, &CurrentParameter); BT_SDP_DEBUG(2, "-- Total UUIDs: %d", TotalUUIDs); /* Retrieve the maximum service record response count from the request */ uint16_t MaxServiceRecordCount = SDP_ReadData16(&CurrentParameter); BT_SDP_DEBUG(2, "-- Max Return Service Count: 0x%04X", MaxServiceRecordCount); struct { SDP_PDUHeader_t SDPHeader; uint16_t TotalServiceRecordCount; uint16_t CurrentServiceRecordCount; uint8_t ResponseData[100]; } ResponsePacket; uint8_t AddedServiceHandles = 0; /* Create a pointer to the buffer to indicate the current location for response data to be added */ void* CurrResponsePos = ResponsePacket.ResponseData; /* Search through the global service list an item at a time */ for (uint8_t CurrTableItem = 0; CurrTableItem < (sizeof(SDP_Services_Table) / sizeof(void*)); CurrTableItem++) { /* Read in a pointer to the current UUID table entry's Attribute table */ ServiceAttributeTable_t* CurrAttributeTable = pgm_read_ptr(&SDP_Services_Table[CurrTableItem]); if (!(SDP_SearchServiceTable(UUIDList, TotalUUIDs, CurrAttributeTable))) continue; BT_SDP_DEBUG(2, " -- Found search match in table"); /* Retrieve a PROGMEM pointer to the value of the service's record handle */ const void* AttributeValue = SDP_GetAttributeValue(CurrAttributeTable, SDP_ATTRIBUTE_ID_SERVICERECORDHANDLE); /* Copy over the service record handle to the response list */ uint8_t AttrHeaderSize; uint8_t AttrSize = SDP_GetLocalAttributeContainerSize(AttributeValue, &AttrHeaderSize); memcpy_P(CurrResponsePos, AttributeValue + AttrHeaderSize, AttrSize); CurrResponsePos += AttrHeaderSize + AttrSize; AddedServiceHandles++; } /* Continuation state - always zero */ SDP_WriteData8(&CurrResponsePos, 0); /* Fill out the service record count values in the returned packet */ ResponsePacket.TotalServiceRecordCount = SwapEndian_16(AddedServiceHandles); ResponsePacket.CurrentServiceRecordCount = ResponsePacket.TotalServiceRecordCount; /* Calculate the total parameter length that is to be sent, including the fixed return parameters, the created service handle list and the SDP continuation state */ uint16_t ParamLength = (ResponsePacket.CurrentServiceRecordCount << 2) + sizeof(ResponsePacket.CurrentServiceRecordCount) + sizeof(ResponsePacket.TotalServiceRecordCount) + sizeof(uint8_t); /* Fill in the response packet's header */ ResponsePacket.SDPHeader.PDU = SDP_PDU_SERVICESEARCHRESPONSE; ResponsePacket.SDPHeader.TransactionID = SDPHeader->TransactionID; ResponsePacket.SDPHeader.ParameterLength = SwapEndian_16(ParamLength); BT_SDP_DEBUG(1, ">> Service Search Response"); /* Send the completed response packet to the sender */ Bluetooth_SendPacket(&ResponsePacket, (sizeof(ResponsePacket.SDPHeader) + ParamLength), Channel); }