public string GetPV(string pv)
        {
            try
            {
                EpicsWrapper.EpicsReturnValue retVal;

                if (cache.Keys.Contains(pv) && cache[pv].LastUpdated + expires > DateTime.UtcNow)
                {
                    retVal = cache[pv].Value;
                }
                else
                {
                    retVal = _epics.GetPV(pv, false);
                    addToCache(pv, retVal);
                }

                return ConvertToJson(retVal);
            }
            catch (Exception err)
            {
                EpicsReturnValue retVal = new EpicsReturnValue();
                retVal.Name = pv;
                retVal.Error = err.Message;
                return ConvertToJson(retVal);
            }
        }
        //public async Task<EpicsReturnValue> GetPVAsync(string pvname, bool waveformAsString)
        //{
        //    EpicsReturnValue retVal = new EpicsReturnValue();
        //    retVal.Name = pvname;
        //    try
        //    {
        //        if (!_channels.ContainsKey(pvname))
        //        {
        //            createChannel(pvname);
        //        }
        //        Type chtype = _channels[pvname].ChannelDefinedType;
        //        uint numelem = _channels[pvname].ChannelDataCount;
        //        if (numelem > 1 && chtype == typeof(byte))
        //        {
        //            //It is probably a waveform of some sort
        //            Task<byte[]> wave = _channels[pvname].GetAsync<byte[]>();
        //            byte[] waveContents = await wave;
        //            retVal.Type = "Waveform";
        //            if (waveformAsString)
        //            {
        //                retVal.Value = waveformToString(waveContents);
        //            }
        //            else
        //            {
        //                retVal.Value = wave;
        //            }
        //        }
        //        else if (chtype == typeof(Enum))
        //        {
        //            //For enums (bo, bi, mbbi, mbbo) get the numerical value and the string value (may be empty)
        //            Task<string> sval = _channels[pvname].GetAsync<string>();
        //            Task<int> val = _channels[pvname].GetAsync<int>();
        //            await Task.WhenAll(sval, val);
        //            retVal.Type = chtype.Name.ToString();
        //            retVal.Value = await val;
        //            retVal.StrValue = await sval;
        //        }
        //        else
        //        {
        //            //Simple value
        //            Task<object> val = _channels[pvname].GetAsync<object>();
        //            retVal.Type = chtype.Name.ToString();
        //            retVal.Value = await val;
        //            retVal.StrValue = retVal.Value.ToString();
        //        }
        //    }
        //    catch (Exception er)
        //    {
        //        retVal.Error = er.Message;
        //    }
        //    return retVal;
        //}
        public EpicsReturnValue GetPV(string pvname, bool waveformAsString)
        {
            EpicsReturnValue retVal = new EpicsReturnValue();
            retVal.Name = pvname;

            try
            {

                //Double checking to ensure thread safety
                if (!_channels.ContainsKey(pvname))     //First check
                {
                    lock (channelsLock)
                    {
                        if (!_channels.ContainsKey(pvname))     //Second check
                        {
                            createChannel(pvname);
                        }
                    }
                }

                Type chtype = _channels[pvname].ChannelDefinedType;
                uint numelem = _channels[pvname].ChannelDataCount;

                object value = null;
                if (numelem > 1 && chtype == typeof(byte))
                {
                    //It is probably a waveform of some sort
                    byte[] val = _channels[pvname].Get<byte[]>();
                    retVal.Type = "Waveform";
                    if (waveformAsString)
                    {
                        retVal.Value = waveformToString(val);
                    }
                    else
                    {
                        retVal.Value = val;
                    }
                }
                else if (chtype == typeof(Enum))
                {
                    //For enums (bo, bi, mbbi, mbbo) get the numerical value and the string value (may be empty)
                    string svalue = _channels[pvname].Get<string>();
                    value = _channels[pvname].Get<int>();
                    retVal.Type = chtype.Name.ToString();
                    retVal.Value = value;
                    retVal.StrValue = svalue;
                }
                else
                {
                    //Simple value
                    value = _channels[pvname].Get<object>();
                    retVal.Type = chtype.Name.ToString();
                    retVal.Value = value;
                    retVal.StrValue = value.ToString();
                }
            }
            catch (Exception er)
            {
                retVal.Error = er.Message;
            }

            return retVal;
        }
        public string GetWaveformDehexedDecompressed(string pv)
        {
            try
            {
                EpicsWrapper.EpicsReturnValue retVal;

                if (cache.Keys.Contains(pv) && cache[pv].LastUpdated + expires > DateTime.UtcNow)
                {
                    retVal = cache[pv].Value;
                }
                else
                {
                    retVal = _epics.GetPV(pv, true);
                    retVal.Value = unzip(dehex(retVal.Value.ToString()));
                    addToCache(pv, retVal);
                }

                return ConvertToJson(retVal);
            }
            catch (Exception err)
            {
                EpicsReturnValue retVal = new EpicsReturnValue();
                retVal.Name = pv;
                retVal.Error = err.Message;
                return ConvertToJson(retVal);
            }
        }
        private static string ConvertToJson(EpicsReturnValue retVal)
        {
            try
            {
                var serializer = new JavaScriptSerializer();
                var serializedResult = serializer.Serialize(retVal);

                return serializedResult;
            }
            catch (Exception err)
            {
                return "{}";
            }
        }