/** * Assemble an iBeacon payload. * * @param[in] uuid Beacon network ID. iBeacon operators use this value * to group their iBeacons into a single network, a single region and * identify their organization among others. * * @param[in] majNum Beacon major group ID. iBeacon exploitants may use * this field to divide the region into subregions, their network into * subnetworks. * * @param[in] minNum Identifier of the Beacon in its subregion. * * @param[in] transmitPower Measured transmit power of the beacon at 1 * meter. Scanners use this parameter to approximate the distance * to the beacon. * * @param[in] companyIDIn ID of the beacon manufacturer. */ Payload( const uint8_t *uuid, uint16_t majNum, uint16_t minNum, uint8_t transmitPower, uint16_t companyIDIn ) : companyID(companyIDIn), ID(0x02), len(0x15), majorNumber(__REV16(majNum)), minorNumber(__REV16(minNum)), txPower(transmitPower) { memcpy(proximityUUID, uuid, 16); }
// ================================ Inner use ================================== void Sound_t::AddCmd(uint8_t AAddr, uint16_t AData) { VsCmd_t FCmd; FCmd.OpCode = VS_WRITE_OPCODE; FCmd.Address = AAddr; FCmd.Data = __REV16(AData); // Add cmd to queue chMBPost(&CmdBox, FCmd.Msg, TIME_INFINITE); StartTransmissionIfNotBusy(); }
/***************************************************************************//** * @brief * Perform a SCSI Write(10) command. * * @param[in] lba * Sector address (LBA) of first sector to write. * * @param[in] sectors * Number of sectors to write. * * @param[out] data * Data buffer containing data to be written. * * @return * Returns true on success, false otherwise. ******************************************************************************/ bool MSDSCSI_Write10(uint32_t lba, uint16_t sectors, const void *data) { EFM32_ALIGN(4) MSDBOT_CBW_TypeDef cbw __attribute__ ((aligned(4))) = CBW_SCSI_WRITE10_INIT_DEFAULT; MSDSCSI_Write10_TypeDef *cb = (MSDSCSI_Write10_TypeDef*) &cbw.CBWCB; cbw.dCBWDataTransferLength = sectors * lbaSize; cb->Lba = __REV(lba); cb->TransferLength = __REV16(sectors); if ((uint32_t) MSDBOT_Xfer(&cbw, (void*) data) == cbw.dCBWDataTransferLength) return true; return false; }
/** * @brief Cal CRC16 for YModem Packet * @param data * @param length * @retval CRC value */ uint16_t Cal_CRC16(const uint8_t* data, uint32_t size) { uint32_t crc = 0; const uint8_t* dataEnd = data+size; #ifdef USE_CRC_PERIPH /* Reset CRC data register */ CRC_ResetDR(); while(data < dataEnd) { crc = CRC_CalcCRC16bits(__REV16(*(uint16_t *)data)); data+=2; } #else /* USE_CRC_SOFTWARE */ while(data<dataEnd) { crc = UpdateCRC16(crc,*data++); } crc = UpdateCRC16(crc,0); crc = UpdateCRC16(crc,0); #endif /* USE_CRC_PERIPH */ return (crc&0xffffu); }
/**************************************************************************//** * @brief * Parse a SCSI command. * A minimal, yet sufficient SCSI command subset is supported. *****************************************************************************/ static void ProcessScsiCdb(void) { MSDSCSI_Inquiry_TypeDef *cbI; MSDSCSI_RequestSense_TypeDef *cbRS; MSDSCSI_ReadCapacity_TypeDef *cbRC; MSDSCSI_Read10_TypeDef *cbR10; MSDSCSI_Write10_TypeDef *cbW10; EFM32_ALIGN(4) static MSDSCSI_ReadCapacityData_TypeDef ReadCapData __attribute__ ((aligned(4))); pCmdStatus->valid = false; pCmdStatus->xferType = XFER_MEMORYMAPPED; pCmdStatus->maxBurst = MAX_BURST; switch (pCbw->CBWCB[ 0 ]) { case SCSI_INQUIRY: cbI = (MSDSCSI_Inquiry_TypeDef*) &pCbw->CBWCB; if ((cbI->Evpd == 0) && (cbI->PageCode == 0)) { /* Standard Inquiry data request */ pCmdStatus->valid = true; pCmdStatus->direction = DIR_DATA_IN; pCmdStatus->pData = (uint8_t*) &InquiryData; pCmdStatus->xferLen = EFM32_MIN(SCSI_INQUIRYDATA_LEN, __REV16(cbI->AllocationLength)); } break; case SCSI_REQUESTSENSE: cbRS = (MSDSCSI_RequestSense_TypeDef*) &pCbw->CBWCB; if ((cbRS->Desc == 0) && (cbRS->Reserved1 == 0) && (cbRS->Reserved2 == 0) && (cbRS->Reserved3 == 0)) { pCmdStatus->valid = true; pCmdStatus->direction = DIR_DATA_IN; pCmdStatus->pData = (uint8_t*) pSenseData; pCmdStatus->xferLen = EFM32_MIN(SCSI_REQUESTSENSEDATA_LEN, cbRS->AllocationLength); pSenseData = (MSDSCSI_RequestSenseData_TypeDef*) &NoSenseData; } break; case SCSI_READCAPACITY: cbRC = (MSDSCSI_ReadCapacity_TypeDef*) &pCbw->CBWCB; if ((cbRC->Pmi == 0) && (cbRC->Lba == 0)) { ReadCapData.LogicalBlockAddress = __REV(MSDDMEDIA_GetSectorCount() - 1); ReadCapData.LogicalBlockLength = __REV(512); pCmdStatus->valid = true; pCmdStatus->direction = DIR_DATA_IN; pCmdStatus->pData = (uint8_t*) &ReadCapData; pCmdStatus->xferLen = SCSI_READCAPACITYDATA_LEN; } break; case SCSI_READ10: cbR10 = (MSDSCSI_Read10_TypeDef*) &pCbw->CBWCB; pCmdStatus->direction = DIR_DATA_IN; pCmdStatus->valid = MSDDMEDIA_CheckAccess(pCmdStatus, __REV(cbR10->Lba), __REV16(cbR10->TransferLength)); break; case SCSI_WRITE10: cbW10 = (MSDSCSI_Write10_TypeDef*) &pCbw->CBWCB; pCmdStatus->direction = DIR_DATA_OUT; pCmdStatus->valid = MSDDMEDIA_CheckAccess(pCmdStatus, __REV(cbW10->Lba), __REV16(cbW10->TransferLength)); break; case SCSI_TESTUNIT_READY: pCmdStatus->valid = true; pCmdStatus->direction = pCbw->Direction; pCmdStatus->xferLen = 0; break; case SCSI_STARTSTOP_UNIT: pCmdStatus->valid = true; pCmdStatus->direction = pCbw->Direction; pCmdStatus->xferLen = 0; pCmdStatus->xferType = XFER_INDIRECT; break; } if (!pCmdStatus->valid) { pCmdStatus->xferLen = 0; pCmdStatus->direction = pCbw->Direction; pSenseData = (MSDSCSI_RequestSenseData_TypeDef*) &IllegalSenseData; } }
// TODO(rqou): Move this elsewhere // TODO(rqou): This entire function is a hack static portTASK_FUNCTION_PROTO(radioTask, pvParameters) { (void) pvParameters; // TODO(rqou): More intelligent interleaved uint32_t code_received_to = 0; uint32_t code_received_len = 0; int got_a_packet = 0; int should_harass = 0; const uint32_t CHUNK_SIZE = 64; // TODO(rqou): Hack uint8_t txbuf[64]; // TODO(rqou): Ugly uglly uint64_t host_addr = 0; // TODO(rqou): Remove this (why does this crash anyways?) int started_angelic = 0; while (1) { uint8_t *buf; size_t len; if (!got_a_packet && should_harass) { // Harass host xbee_api_packet *packetOut = (xbee_api_packet *)(txbuf); packetOut->xbee_api_magic = XBEE_MAGIC; int payloadLen = sizeof(xbee_tx64_header) + sizeof(tenshi_bulk_chunkreq); packetOut->length = __REV16(payloadLen); packetOut->payload.tx64.xbee_api_type = XBEE_API_TYPE_TX64; packetOut->payload.tx64.frameId = 0; packetOut->payload.tx64.xbee_dest_addr = host_addr; packetOut->payload.tx64.options = 0; tenshi_bulk_chunkreq *bulk_chunkreq = (tenshi_bulk_chunkreq *)(packetOut->payload.tx64.data); bulk_chunkreq->ident = TENSHI_NAIVE_BULK_CHUNKREQ_IDENT; bulk_chunkreq->stream_id = 0; bulk_chunkreq->start_addr = code_received_to; if (code_received_to + CHUNK_SIZE > code_received_len) { bulk_chunkreq->end_addr = code_received_len; } else { bulk_chunkreq->end_addr = code_received_to + CHUNK_SIZE; } xbee_fill_checksum(packetOut); // TODO(rqou): Asynchronous? // TODO(rqou): Abstract away the +4 properly // TODO(rqou): Error handling void *txn = uart_serial_send_data(radio_driver, txbuf, payloadLen + 4); while ((uart_serial_send_status(radio_driver, txn) != UART_SERIAL_SEND_DONE) && (uart_serial_send_status(radio_driver, txn) != UART_SERIAL_SEND_ERROR)) {} uart_serial_send_finish(radio_driver, txn); } got_a_packet = 0; buf = uart_serial_receive_packet(radio_driver, &len, 0); if (!buf) { // TODO(rqou): Proper timer, why the f*ck do I need to copy this here? vTaskDelay(20 / portTICK_RATE_MS); continue; } xbee_api_packet *packetIn = (xbee_api_packet *)buf; if (!xbee_verify_checksum(packetIn)) { vPortFree(buf); // TODO(rqou): Proper timer, why the f*ck do I need to copy this here? vTaskDelay(20 / portTICK_RATE_MS); continue; } if (packetIn->payload.xbee_api_type != XBEE_API_TYPE_RX64) { vPortFree(buf); // TODO(rqou): Proper timer, why the f*ck do I need to copy this here? vTaskDelay(20 / portTICK_RATE_MS); continue; } // ident byte for PiEMOS framing switch (packetIn->payload.rx64.data[0]) { case PIER_INCOMINGDATA_IDENT: { pier_incomingdata *incomingData = (pier_incomingdata *)(packetIn->payload.rx64.data); // TODO(rqou): This code is terribly hardcoded. for (int i = 0; i < 7; i++) { PiEMOSAnalogVals[i] = (float)((int)incomingData->analog[i] - 127) / 127.0f * 100.0f; } for (int i = 0; i < 8; i++) { PiEMOSDigitalVals[i] = !!(incomingData->digital & (1 << i)); } } break; // Naive bulk protocol case TENSHI_NAIVE_BULK_START_IDENT: { tenshi_bulk_start *bulk_start = (tenshi_bulk_start *)(packetIn->payload.rx64.data); // TODO(rqou): What happens if I already have one? // TODO(rqou): Stream ID? code_buffer = pvPortMalloc(bulk_start->length); code_received_to = 0; code_buffer_len = code_received_len = bulk_start->length; got_a_packet = 1; should_harass = 1; // TODO(rqou): Refactor this logic host_addr = packetIn->payload.rx64.xbee_src_addr; } break; case TENSHI_NAIVE_BULK_CHUNK_IDENT: { tenshi_bulk_chunk *bulk_chunk = (tenshi_bulk_chunk *)(packetIn->payload.rx64.data); memcpy(code_buffer + bulk_chunk->start_addr, bulk_chunk->data, bulk_chunk->end_addr - bulk_chunk->start_addr); // TODO(rqou): Properly handle out-of-order code_received_to = bulk_chunk->end_addr; got_a_packet = 1; if (code_received_to == code_received_len) { xbee_api_packet *packetOut = (xbee_api_packet *)(txbuf); packetOut->xbee_api_magic = XBEE_MAGIC; int payloadLen = sizeof(xbee_tx64_header) + sizeof(tenshi_bulk_stop); packetOut->length = __REV16(payloadLen); packetOut->payload.tx64.xbee_api_type = XBEE_API_TYPE_TX64; packetOut->payload.tx64.frameId = 0; packetOut->payload.tx64.xbee_dest_addr = packetIn->payload.rx64.xbee_src_addr; packetOut->payload.tx64.options = 0; tenshi_bulk_stop *bulk_stop = (tenshi_bulk_stop *)(packetOut->payload.tx64.data); bulk_stop->ident = TENSHI_NAIVE_BULK_STOP_IDENT; bulk_stop->stream_id = 0; xbee_fill_checksum(packetOut); should_harass = 0; // TODO(rqou): Asynchronous? // TODO(rqou): Abstract away the +4 properly // TODO(rqou): Error handling void *txn = uart_serial_send_data(radio_driver, txbuf, payloadLen + 4); while ((uart_serial_send_status(radio_driver, txn) != UART_SERIAL_SEND_DONE) && (uart_serial_send_status(radio_driver, txn) != UART_SERIAL_SEND_ERROR)) {} uart_serial_send_finish(radio_driver, txn); if (!started_angelic) { started_angelic = 1; xTaskCreate(angelicTask, "Angelic", 2048, NULL, tskIDLE_PRIORITY, NULL); } } } break; default: // TODO(rqou): Report error or something? break; } vPortFree(buf); // TODO(rqou): Proper timer vTaskDelay(20 / portTICK_RATE_MS); } }
extern void application_task(void) { UINT bytesread = 0; WAVE_FormatTypeDef waveformat; switch (appState) { case APPSTATE_IDLE: if (usbConnected) { appState = APPSTATE_MOUNT_FS; } break; case APPSTATE_GEN_SINE: waveformat.SampleRate = SINE_GEN_AUDIO_SAMPLE_RATE; waveformat.FileSize = SINE_GEN_AUDIO_SAMPLE_RATE * SINE_GEN_DURATION * \ sizeof(int16_t) + sizeof(WAVE_FormatTypeDef); waveformat.NbrChannels = CHANNEL_MONO; WavePlayerStart(waveformat, getDataSineCB, 70); break; case APPSTATE_MOUNT_FS: if (f_mount(&USBDISKFatFs, (TCHAR const*)USBDISKPath, 0 ) != FR_OK ) { /* FatFs initialization fails */ Error_Handler(); } else { appState = APPSTATE_WRITE; } break; case APPSTATE_UMOUNT_FS: f_mount(NULL, (TCHAR const*)"", 1); appState = APPSTATE_IDLE; break; case APPSTATE_WRITE: if (f_open(&FileWrite, WAVE_NAME_COMPLETO, FA_CREATE_ALWAYS | FA_WRITE) != FR_OK) { Error_Handler(); } else { waveformat.SampleRate = SINE_GEN_AUDIO_SAMPLE_RATE; waveformat.FileSize = SINE_GEN_AUDIO_SAMPLE_RATE * SINE_GEN_DURATION * \ sizeof(int16_t) + sizeof(WAVE_FormatTypeDef); waveformat.NbrChannels = WAVE_CHANNEL_MONO; waveformat.ByteRate = SINE_GEN_AUDIO_SAMPLE_RATE * WAVE_CHANNEL_MONO * sizeof(int16_t); waveformat.BitPerSample = __REV16(WAVE_16_BIT_PER_SAMPLE); waveformat.SubChunk2Size = SINE_GEN_AUDIO_SAMPLE_RATE * SINE_GEN_DURATION * sizeof(int16_t); WaveRecord(&FileWrite, waveformat, getDataSineCB); f_close(&FileWrite); appState = APPSTATE_PLAY; } break; case APPSTATE_PLAY: if (f_open(&FileRead, WAVE_NAME_COMPLETO, FA_READ) != FR_OK) { Error_Handler(); } else { /* Read sizeof(WaveFormat) from the selected file */ f_read (&FileRead, &waveformat, sizeof(waveformat), &bytesread); WavePlayerStart(waveformat, getDataCB, 70); f_close(&FileRead); } break; default: appState = APPSTATE_IDLE; break; } }