private IEnumerator Transmit(Callback callback = null)
        {
            RTLog.Notify("ModuleRTDataTransmitter::Transmit");
            var msg       = new ScreenMessage(String.Format("[{0}]: Starting Transmission...", part.partInfo.title), 4f, ScreenMessageStyle.UPPER_LEFT);
            var msgStatus = new ScreenMessage(String.Empty, 4.0f, ScreenMessageStyle.UPPER_LEFT);

            ScreenMessages.PostScreenMessage(msg);

            isBusy = true;

            while (scienceDataQueue.Any())
            {
                var scienceData = scienceDataQueue[0];
                var dataAmount  = scienceData.dataAmount;
                scienceDataQueue.RemoveAt(0);
                scienceData.triggered = true;

                var subject = ResearchAndDevelopment.GetSubjectByID(scienceData.subjectID);
                if (subject == null)
                {
                    subject = new ScienceSubject("", "", 1, 0, 0);
                }

                int packets = Mathf.CeilToInt(scienceData.dataAmount / PacketSize);

                RnDCommsStream commStream = null;
                if (ResearchAndDevelopment.Instance != null)
                {
                    // pre-calculate the time interval - fix for x64 systems
                    // workaround for issue #136
                    float time1 = Time.time;
                    yield return(new WaitForSeconds(PacketInterval));

                    // get the delta time
                    float x64PacketInterval = (Time.time - time1);
                    RTLog.Notify("Changing RnDCommsStream timeout from {0} to {1}", PacketInterval, x64PacketInterval);

                    //TODO (porting to 1.2): check if scienceData.baseTransmitValue alone or with scienceData.transmitBonus
                    commStream = new RnDCommsStream(subject, scienceData.dataAmount, x64PacketInterval,
                                                    scienceData.baseTransmitValue, false, ResearchAndDevelopment.Instance);
                }
                //StartCoroutine(SetFXModules_Coroutine(modules_progress, 0.0f));
                float power = 0;
                while (packets > 0)
                {
                    power += part.RequestResource("ElectricCharge", PacketResourceCost - power);
                    if (power >= PacketResourceCost * 0.95)
                    {
                        GUIStatus = "Uploading Data...";

                        // remove some power due to transmission
                        power -= PacketResourceCost;

                        // transmitted size
                        float frame = Math.Min(PacketSize, dataAmount);

                        // subtract current packet size from data left to transmit
                        // and clamp it to 1 digit precision to avoid large float precision error (#667)
                        dataAmount -= frame;
                        dataAmount  = (float)Math.Round(dataAmount, 1);

                        packets--;

                        float progress = (scienceData.dataAmount - dataAmount) / scienceData.dataAmount;
                        msgStatus.message = String.Format("[{0}]: Uploading Data... {1:P0}", part.partInfo.title, progress);
                        ScreenMessages.PostScreenMessage(msgStatus);

                        RTLog.Notify("[Transmitter]: Uploading Data... ({0}) - {1} Mits/sec. Packets to go: {2} - Other experiments waiting to transfer: {3}",
                                     scienceData.title, (PacketSize / PacketInterval).ToString("0.00"), packets, scienceDataQueue.Count);

                        // if we've a defined callback parameter so skip to stream each packet
                        if (commStream != null && callback == null)
                        {
                            RTLog.Notify(
                                "[Transmitter]: PacketSize: {0}; Transmitted size (frame): {1}; Data left to transmit (dataAmount): {2}; Packets left (packets): {3}",
                                PacketSize, frame, dataAmount, packets);

                            // use try / catch to prevent NRE spamming in KSP code when RT is used with other mods.
                            try
                            {
                                commStream.StreamData(frame, vessel.protoVessel);
                            }
                            catch (NullReferenceException nre)
                            {
                                RTLog.Notify("A problem occurred during science transmission: {0}", RTLogLevel.LVL2, nre);
                            }

                            // TODO: remove this when fixed in stock
                            // Fix a problem in stock KSP (discovered in 1.1.3, and still here in 1.2.1)
                            // issue #667 ; floating point error in RnDCommsStream.StreamData method when adding to dataIn private field
                            // e.g scienceData.dataAmount is 10 but in the end RnDCommsStream.dataIn will be 9.999999, so the science never
                            //     gets registered to the ResearchAndDevelopment center.
                            if (packets == 0) // check that we have no packet left to send.
                            {
                                // get the private field (dataIn) in RnDCommsStream. This field is subject to floating point rounding error
                                // We handle this problem on our side.
                                var dataIn = RTUtil.GetInstanceField(typeof(RnDCommsStream), commStream, "dataIn");
                                if (dataIn != null)
                                {
                                    // check if we have a delta (e.g. 10 - 9.999999999 will give us a tiny delta)
                                    var delta = scienceData.dataAmount - (float)dataIn;
                                    RTLog.Notify("[Transmitter]: delta: {0}", delta);

                                    // the delta must be positive and less than this constant to push / transmit the remaining size.
                                    // This prevent us pushing packets with too much leftover to transmit (e.g if there was a connection loss).
                                    if ((delta > 0f) && (delta <= PacketRemainingSize))
                                    {
                                        try
                                        {
                                            // we have a delta, try to send the remaining little bit of science
                                            commStream.StreamData(delta, vessel.protoVessel);
                                        }
                                        catch (NullReferenceException nre)
                                        {
                                            RTLog.Notify("A problem occurred during science transmission (delta): {0}",
                                                         RTLogLevel.LVL2, nre);
                                        }
                                    }
                                }
                                else
                                {
                                    RTLog.Notify("[Transmitter]: dataIn is null.");
                                }
                            } // end stock fix
                        }
                        else
                        {
                            RTLog.Notify("[Transmitter]: [DEBUG] commstream is null and no callback");
                        }
                    }
                    else
                    {
                        // not enough power
                        msg.message = String.Format("<b><color=orange>[{0}]: Warning! Not Enough {1}!</color></b>", part.partInfo.title, RequiredResource);
                        ScreenMessages.PostScreenMessage(msg);

                        GUIStatus = String.Format("{0}/{1} {2}", power, PacketResourceCost, RequiredResource);
                    }

                    yield return(new WaitForSeconds(PacketInterval));
                }

                // effectively inform the game that science has been transmitted
                GameEvents.OnTriggeredDataTransmission.Fire(scienceData, vessel, false);
                yield return(new WaitForSeconds(PacketInterval * 2));
            }

            isBusy = false;

            msg.message = String.Format("[{0}]: Done!", part.partInfo.title);
            ScreenMessages.PostScreenMessage(msg);

            if (callback != null)
            {
                callback.Invoke();
            }

            GUIStatus = "Idle";
        }