添加实时数据读取

master
mzhifa 1 year ago
parent e5f395f716
commit 7a6a34c344

@ -31,6 +31,42 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />

@ -1,6 +1,4 @@
using System; using System;
using System.Collections.Generic;
using System.Linq;
using System.Text; using System.Text;
using System.Threading.Tasks; using System.Threading.Tasks;
using Newtonsoft.Json.Linq; using Newtonsoft.Json.Linq;
@ -141,5 +139,26 @@ namespace StartServerWPF.Modules.Main
" -btime " + beginTime.GetDateTimeFormats('s')[0].ToString() + " >outMonitor.txt"; " -btime " + beginTime.GetDateTimeFormats('s')[0].ToString() + " >outMonitor.txt";
return moniSp; return moniSp;
} }
public static string[] ReadApmsJson(string apmsJsonPath)
{
using (StreamReader sr = File.OpenText(apmsJsonPath))
{
JsonTextReader reader = new JsonTextReader(sr);
JObject jobj = (JObject)JToken.ReadFrom(reader);
JObject jordb = JObject.Parse(jobj["channels"].ToString());
string sta = jordb["station"].ToString();
var staList= sta.Split(",");
return staList;
}
}
} }
} }

@ -2,7 +2,8 @@
<PropertyGroup> <PropertyGroup>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net6.0-windows</TargetFramework>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<UseWindowsForms>True</UseWindowsForms> <UseWindowsForms>True</UseWindowsForms>
<Platforms>AnyCPU;x86;x64</Platforms>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<Compile Remove="Fonts\**" /> <Compile Remove="Fonts\**" />

@ -74,6 +74,6 @@ namespace StartServerWPF.Modules.Main.ViewModels
} }
} }
List<string> menuNames = new List<string>() {"首页","实时波形","波形回放","设置","日志", }; List<string> menuNames = new List<string>() {"首页","实时波形","波形回放","设置","日志", };
List<string> viewName = new List<string>() { "MainView", "ChartPlotView", "ChartPlotView", "SetParamView", "LogManagementView"}; List<string> viewName = new List<string>() { "MainView", "ChartPlotRealDataView", "ChartPlotView", "SetParamView", "LogManagementView"};
} }
} }

@ -0,0 +1,45 @@
using System.Configuration;
namespace ZhaoXi.Advanced.MyRedis.Init
{
/// <summary>
/// redis配置文件信息
/// 也可以放到配置文件去
/// </summary>
public sealed class RedisConfigInfo
{
/// <summary>
/// 可写的Redis链接地址
/// format:ip1,ip2
///
/// 默认6379端口
/// </summary>
public string WriteServerList = "127.0.0.1:6379";
/// <summary>
/// 可读的Redis链接地址
/// format:ip1,ip2
/// </summary>
public string ReadServerList = "127.0.0.1:6379";
/// <summary>
/// 最大写链接数
/// </summary>
public int MaxWritePoolSize = 60;
/// <summary>
/// 最大读链接数
/// </summary>
public int MaxReadPoolSize = 60;
/// <summary>
/// 本地缓存到期时间,单位:秒
/// </summary>
public int LocalCacheTime = 180;
/// <summary>
/// 自动重启
/// </summary>
public bool AutoStart = true;
/// <summary>
/// 是否记录日志,该设置仅用于排查redis运行时出现的问题,
/// 如redis工作正常,请关闭该项
/// </summary>
public bool RecordeLog = false;
}
}

@ -0,0 +1,62 @@

using ServiceStack.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ZhaoXi.Advanced.MyRedis.Init
{
/// <summary>
/// Redis管理中心 创建Redis链接
/// </summary>
public class RedisManager
{
/// <summary>
/// redis配置文件信息
/// </summary>
private static RedisConfigInfo RedisConfigInfo = new RedisConfigInfo();
/// <summary>
/// Redis客户端池化管理
/// </summary>
private static PooledRedisClientManager prcManager;
/// <summary>
/// 静态构造方法,初始化链接池管理对象
/// </summary>
static RedisManager()
{
CreateManager();
}
/// <summary>
/// 创建链接池管理对象
/// </summary>
private static void CreateManager()
{
string[] WriteServerConStr = RedisConfigInfo.WriteServerList.Split(',');
string[] ReadServerConStr = RedisConfigInfo.ReadServerList.Split(',');
prcManager = new PooledRedisClientManager(ReadServerConStr, WriteServerConStr,
new RedisClientManagerConfig
{
MaxWritePoolSize = RedisConfigInfo.MaxWritePoolSize,
MaxReadPoolSize = RedisConfigInfo.MaxReadPoolSize,
AutoStart = RedisConfigInfo.AutoStart,
DefaultDb=1
});
}
/// <summary>
/// 客户端缓存操作对象
/// </summary>
public static IRedisClient GetClient()
{
string[] WriteServerConStr = RedisConfigInfo.WriteServerList.Split(':');
var client = new RedisClient(WriteServerConStr[0], Convert.ToInt32(WriteServerConStr[1]),password: "beijingtianxiangguoyue",db:1);
// return prcManager.GetClient();
return client;
}
}
}

@ -0,0 +1,95 @@

using ServiceStack.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using ZhaoXi.Advanced.MyRedis.Init;
namespace ZhaoXi.Advanced.MyRedis.Interface
{
/// <summary>
/// RedisBase类是redis操作的基类继承自IDisposable接口主要用于释放内存
/// </summary>
public abstract class RedisBase : IDisposable
{
public IRedisClient iClient { get; private set; }
/// <summary>
/// 构造时完成链接的打开
/// </summary>
public RedisBase()
{
iClient = RedisManager.GetClient();
}
//public static IRedisClient iClient { get; private set; }
//static RedisBase()
//{
// iClient = RedisManager.GetClient();
//}
private bool _disposed = false;
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
iClient.Dispose();
iClient = null;
}
}
this._disposed = true;
}
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
public void Transcation()
{
using (IRedisTransaction irt = this.iClient.CreateTransaction())
{
try
{
irt.QueueCommand(r => r.Set("key", 20));
irt.QueueCommand(r => r.Increment("key", 1));
irt.Commit(); // 提交事务
}
catch (Exception ex)
{
irt.Rollback();
throw ex;
}
}
}
/// <summary>
/// 清除全部数据 请小心
/// </summary>
public virtual void FlushAll()
{
iClient.FlushAll();
}
/// <summary>
/// 保存数据DB文件到硬盘
/// </summary>
public void Save()
{
iClient.Save();//阻塞式save
}
/// <summary>
/// 异步保存数据DB文件到硬盘
/// </summary>
public void SaveAsync()
{
iClient.SaveAsync();//异步save
}
}
}

@ -30,7 +30,7 @@ namespace StartServerWPF.Modules.MseedChart.Models
public int SamplingFrequency { get; set; } public int SamplingFrequency { get; set; }
public DateTime BeginTime; public DateTime BeginTime=DateTime.Now;
public bool IsVisible = true; public bool IsVisible = true;

@ -25,7 +25,7 @@ namespace StartServerWPF.Modules.MseedChart.Models
//添加Z分量波形 //添加Z分量波形
if (item.dz.Count > 0) if (item.dz.Count > 0)
{ {
axisY.SetRange(item.dz.Min(), item.dz.Max()); axisY.SetRange(0, 6000);
} }
axisY.Title.Text = string.Format("Ch{0}.Z", item.Name); axisY.Title.Text = string.Format("Ch{0}.Z", item.Name);
axisY.Title.DistanceToAxis = distancetoX; axisY.Title.DistanceToAxis = distancetoX;
@ -33,8 +33,8 @@ namespace StartServerWPF.Modules.MseedChart.Models
//添加N分量波形 //添加N分量波形
axisY = new AxisY(curChart.ViewXY); axisY = new AxisY(curChart.ViewXY);
if (item.dn.Count > 0) if (item.dn.Count > 0)
{ {
axisY.SetRange(item.dn.Min(), item.dn.Max()); axisY.SetRange(0, 6000);
} }
axisY.Title.Text = string.Format("Ch{0}.N", item.Name); axisY.Title.Text = string.Format("Ch{0}.N", item.Name);
axisY.Title.DistanceToAxis = distancetoX; axisY.Title.DistanceToAxis = distancetoX;
@ -43,8 +43,8 @@ namespace StartServerWPF.Modules.MseedChart.Models
//添加E分量波形 //添加E分量波形
axisY = new AxisY(curChart.ViewXY); axisY = new AxisY(curChart.ViewXY);
if (item.de.Count > 0) if (item.de.Count > 0)
{ {
axisY.SetRange(item.de.Min(), item.de.Max()); axisY.SetRange(0, 6000);
} }
axisY.Title.Text = string.Format("Ch{0}.E", item.Name); axisY.Title.Text = string.Format("Ch{0}.E", item.Name);
axisY.Title.DistanceToAxis = distancetoX; axisY.Title.DistanceToAxis = distancetoX;
@ -272,5 +272,30 @@ namespace StartServerWPF.Modules.MseedChart.Models
return null; return null;
} }
#region 实时数据解析
public ConcurrentQueue<StationModel> ReadWavesFromJson(string[] stations)
{
ConcurrentQueue<StationModel> temSM = new ConcurrentQueue<StationModel>();
StationModel station = new StationModel();
for (int i = 0; i < stations.Length; i++)
{
station = new StationModel();
station.Name = stations[i].Trim();
station.dz.Add(0);
station.dn.Add(0);
station.de.Add(0);
temSM.Enqueue(station);
}
temSM.Reverse();
return temSM;
}
#endregion
} }
} }

@ -0,0 +1,40 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace StartServerWPF.Modules.MseedChart
{
public class Mseed2asciiApi
{
public delegate void LoopCallbackHandler(AsciiDataStruct asciiData);
[DllImport("mseedC.dll", EntryPoint = "MseedDatas")]
public extern static int MseedDatas(int a, string[] name);
//public extern static int MseedDatas(Byte[] bytes, int lenght);
[DllImport("mseedC.dll", EntryPoint = "bufferMseedData")]
public extern static int bufferMseedData(int argc, Byte[] argv);
[DllImport("mseedC.dll", EntryPoint = "testc")]
public extern static int testc(int a, int b);
[DllImport("mseedC.dll")]
public static extern void MseedDatasCallFun(LoopCallbackHandler callback);
}
[StructLayout(LayoutKind.Sequential)]
public struct AsciiDataStruct
{
public string sid;
// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
public string starttime; //!< Time of first sample
// [MarshalAs(UnmanagedType.ByValArray, SizeConst = 30)]
public string endtime; //!< Time of last sample
public double samprate; //!< Nominal sample rate (Hz)
public Int64 samplecnt; //!< Number of samples in trace coverage
public UInt64 datasize; //!< Size of datasamples buffer in bytes
public Int64 numsamples; //!< Number of data samples in datasamples
public char sampletype; //!< Sample type code, see @ref sample-types
public char samplesize;
public System.IntPtr datasamples; //!< Data samples, \a numsamples of type \a sampletype
}
}

@ -18,7 +18,9 @@ namespace StartServerWPF.Modules.MseedChart
public void RegisterTypes(IContainerRegistry containerRegistry) public void RegisterTypes(IContainerRegistry containerRegistry)
{ {
containerRegistry.RegisterForNavigation<ChartPlotView>(); containerRegistry.RegisterForNavigation<ChartPlotView>();
containerRegistry.RegisterForNavigation<ChartPlotRealDataView>();
containerRegistry.RegisterSingleton<ChartPlotViewModel>(); containerRegistry.RegisterSingleton<ChartPlotViewModel>();
containerRegistry.RegisterSingleton<ChartPlotRealDataViewModel>();
} }
} }

@ -0,0 +1,299 @@
using ZhaoXi.Advanced.MyRedis.Interface;
using ServiceStack.Redis;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.IO;
using ServiceStack;
using System.Collections;
using System.Runtime.Serialization.Formatters.Binary;
using System.Runtime.Serialization;
using static System.Net.WebRequestMethods;
namespace ZhaoXi.Advanced.MyRedis.Service
{
/// <summary>
/// Redis list的实现为一个双向链表即可以支持反向查找和遍历更方便操作不过带来了部分额外的内存开销
/// Redis内部的很多实现包括发送缓冲队列等也都是用的这个数据结构。
/// </summary>
public class RedisListService : RedisBase
{
#region 赋值
/// <summary>
/// 从左侧向list中添加值
/// </summary>
public void LPush(string key, string value)
{
base.iClient.PushItemToList(key, value);
}
/// <summary>
/// 从左侧向list中添加值并设置过期时间
/// </summary>
public void LPush(string key, string value, DateTime dt)
{
base.iClient.PushItemToList(key, value);
base.iClient.ExpireEntryAt(key, dt);
}
/// <summary>
/// 从左侧向list中添加值设置过期时间
/// </summary>
public void LPush(string key, string value, TimeSpan sp)
{
base.iClient.PushItemToList(key, value);
base.iClient.ExpireEntryIn(key, sp);
}
/// <summary>
/// 从右侧向list中添加值
/// </summary>
public void RPush(string key, string value)
{
base.iClient.PrependItemToList(key, value);
}
/// <summary>
/// 从右侧向list中添加值并设置过期时间
/// </summary>
public void RPush(string key, string value, DateTime dt)
{
base.iClient.PrependItemToList(key, value);
base.iClient.ExpireEntryAt(key, dt);
}
/// <summary>
/// 从右侧向list中添加值并设置过期时间
/// </summary>
public void RPush(string key, string value, TimeSpan sp)
{
base.iClient.PrependItemToList(key, value);
base.iClient.ExpireEntryIn(key, sp);
}
/// <summary>
/// 添加key/value
/// </summary>
public void Add(string key, string value)
{
base.iClient.AddItemToList(key, value);
}
/// <summary>
/// 添加key/value ,并设置过期时间
/// </summary>
public void Add(string key, string value, DateTime dt)
{
base.iClient.AddItemToList(key, value);
base.iClient.ExpireEntryAt(key, dt);
}
/// <summary>
/// 添加key/value。并添加过期时间
/// </summary>
public void Add(string key, string value, TimeSpan sp)
{
base.iClient.AddItemToList(key, value);
base.iClient.ExpireEntryIn(key, sp);
}
/// <summary>
/// 为key添加多个值
/// </summary>
public void Add(string key, List<string> values)
{
base.iClient.AddRangeToList(key, values);
}
/// <summary>
/// 为key添加多个值并设置过期时间
/// </summary>
public void Add(string key, List<string> values, DateTime dt)
{
base.iClient.AddRangeToList(key, values);
base.iClient.ExpireEntryAt(key, dt);
}
/// <summary>
/// 为key添加多个值并设置过期时间
/// </summary>
public void Add(string key, List<string> values, TimeSpan sp)
{
base.iClient.AddRangeToList(key, values);
base.iClient.ExpireEntryIn(key, sp);
}
#endregion
#region 获取值
/// <summary>
/// 获取list中key包含的数据数量
/// </summary>
public long Count(string key)
{
return base.iClient.GetListCount(key);
}
/// <summary>
/// 获取key包含的所有数据集合
/// </summary>
public List<string> Get(string key)
{
return base.iClient.GetAllItemsFromList(key);
}
/// <summary>
/// 获取key中下标为star到end的值集合
/// </summary>
public List<string> Get(string key, int star, int end)
{
return base.iClient.GetRangeFromList(key, star, end);
}
#endregion
#region 阻塞命令
/// <summary>
/// 阻塞命令从list为key的尾部移除一个值并返回移除的值阻塞时间为sp
/// </summary>
public string BlockingPopItemFromList(string key, TimeSpan? sp)
{
return base.iClient.BlockingPopItemFromList(key, sp);
}
/// <summary>
/// 阻塞命令从多个list中尾部移除一个值,并返回移除的值&key阻塞时间为sp
/// </summary>
public ItemRef BlockingPopItemFromLists(string[] keys, TimeSpan? sp)
{
return base.iClient.BlockingPopItemFromLists(keys, sp);
}
/// <summary>
/// 阻塞命令从list中keys的尾部移除一个值并返回移除的值阻塞时间为sp
/// </summary>
public string BlockingDequeueItemFromList(string key, TimeSpan? sp)
{
return base.iClient.BlockingDequeueItemFromList(key, sp);
}
/// <summary>
/// 阻塞命令从多个list中尾部移除一个值并返回移除的值&key阻塞时间为sp
/// </summary>
public ItemRef BlockingDequeueItemFromLists(string[] keys, TimeSpan? sp)
{
return base.iClient.BlockingDequeueItemFromLists(keys, sp);
}
/// <summary>
/// 阻塞命令从list中一个fromkey的尾部移除一个值添加到另外一个tokey的头部并返回移除的值阻塞时间为sp
/// </summary>
public string BlockingPopAndPushItemBetweenLists(string fromkey, string tokey, TimeSpan? sp)
{
return base.iClient.BlockingPopAndPushItemBetweenLists(fromkey, tokey, sp);
}
#endregion
#region 删除
/// <summary>
/// 从尾部移除数据,返回移除的数据
/// </summary>
public string PopItemFromList(string key)
{
var sa = base.iClient.CreateSubscription();
return base.iClient.PopItemFromList(key);
}
/// <summary>
/// 从尾部移除数据,返回移除的数据
/// </summary>
public string DequeueItemFromList(string key)
{
return base.iClient.DequeueItemFromList(key);
}
/// <summary>
/// 移除list中key/value,与参数相同的值,并返回移除的数量
/// </summary>
public long RemoveItemFromList(string key, string value)
{
return base.iClient.RemoveItemFromList(key, value);
}
/// <summary>
/// 从list的尾部移除一个数据返回移除的数据
/// </summary>
public string RemoveEndFromList(string key)
{
return base.iClient.RemoveEndFromList(key);
}
/// <summary>
/// 从list的头部移除一个数据返回移除的值
/// </summary>
public string RemoveStartFromList(string key)
{
return base.iClient.RemoveStartFromList(key);
}
#endregion
#region 其它
/// <summary>
/// 从一个list的尾部移除一个数据添加到另外一个list的头部并返回移动的值
/// </summary>
public string PopAndPushItemBetweenLists(string fromKey, string toKey)
{
return base.iClient.PopAndPushItemBetweenLists(fromKey, toKey);
}
public void TrimList(string key, int start, int end)
{
base.iClient.TrimList(key, start, end);
}
#endregion
#region 发布订阅
public void Publish(string channel, string message)
{
base.iClient.PublishMessage(channel, message);
}
public void Subscribe(string channel, Action<string, byte[], IRedisSubscription> actionOnMessage)
{
var subscription = base.iClient.CreateSubscription();
subscription.OnSubscribe = c =>
{
Console.WriteLine($"订阅频道{c}");
Console.WriteLine();
};
//取消订阅
subscription.OnUnSubscribe = c =>
{
Console.WriteLine($"取消订阅 {c}");
Console.WriteLine();
};
subscription.OnMessage += (c, s) =>
{
// actionOnMessage(c, s, subscription);
};
subscription.OnMessageBytes += (c, s) =>
{
// ByteToFile(s, "test.mseed");
actionOnMessage(c, s, subscription);
};
Console.WriteLine($"开始启动监听 {channel}");
subscription.SubscribeToChannels(channel); //blocking
}
public void UnSubscribeFromChannels(string channel)
{
var subscription = base.iClient.CreateSubscription();
subscription.UnSubscribeFromChannels(channel);
}
public static bool ByteToFile(byte[] byteArray, string fileName)
{
bool result = false;
try
{
using (FileStream fs = new FileStream(fileName, FileMode.OpenOrCreate, FileAccess.Write))
{
fs.Write(byteArray, 0, byteArray.Length);
result = true;
}
}
catch
{
result = false;
}
return result;
}
#endregion
}
}

@ -0,0 +1,136 @@
using ZhaoXi.Advanced.MyRedis.Interface;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace ZhaoXi.Advanced.MyRedis.Service
{
/// <summary>
/// key-value 键值对:value可以是序列化的数据
/// </summary>
public class RedisStringService : RedisBase
{
#region 赋值
/// <summary>
/// 设置key的value
/// </summary>
public bool Set<T>(string key, T value)
{
//iClient.Db =2;
return base.iClient.Set<T>(key, value);
}
/// <summary>
/// 设置key的value并设置过期时间
/// </summary>
public bool Set<T>(string key, T value, DateTime dt)
{
//iClient.Db = 2;
return base.iClient.Set<T>(key, value, dt);
}
/// <summary>
/// 设置key的value并设置过期时间
/// </summary>
public bool Set<T>(string key, T value, TimeSpan sp)
{
//iClient.Db = 2;
return base.iClient.Set<T>(key, value, sp);
}
/// <summary>
/// 设置多个key/value 可以一次保存多个key value ---多个key value 不是分多次,是一个独立的命令;
/// </summary>
public void Set(Dictionary<string, string> dic)
{
//iClient.Db = 2;
base.iClient.SetAll(dic);
}
#endregion
#region 追加
/// <summary>
/// 在原有key的value值之后追加value,没有就新增一项
/// </summary>
public long Append(string key, string value)
{
return base.iClient.AppendToValue(key, value);
}
#endregion
#region 获取值
/// <summary>
/// 获取key的value值
/// </summary>
public string Get(string key)
{
return base.iClient.GetValue(key);
}
/// <summary>
/// 获取多个key的value值
/// </summary>
public List<string> Get(List<string> keys)
{
return base.iClient.GetValues(keys);
}
/// <summary>
/// 获取多个key的value值
/// </summary>
public List<T> Get<T>(List<string> keys)
{
return base.iClient.GetValues<T>(keys);
}
#endregion
#region 获取旧值赋上新值
/// <summary>
/// 获取旧值赋上新值
/// </summary>
public string GetAndSetValue(string key, string value)
{
return base.iClient.GetAndSetValue(key, value);
}
#endregion
#region 辅助方法
/// <summary>
/// 获取值的长度
/// </summary>
public long GetLength(string key)
{
return base.iClient.GetStringCount(key);
}
/// <summary>
/// 自增1返回自增后的值 保存的是10 调用后,+1 返回11
/// </summary>
public long Incr(string key)
{
return base.iClient.IncrementValue(key);
}
/// <summary>
/// 自增count返回自增后的值 自定义自增的步长值
/// </summary>
public long IncrBy(string key, int count)
{
return base.iClient.IncrementValueBy(key, count);
}
/// <summary>
/// 自减1返回自减后的值Redis操作是单线程操作不会出现超卖的情况
/// </summary>
public long Decr(string key)
{
return base.iClient.DecrementValue(key);
}
/// <summary>
/// 自减count ,返回自减后的值
/// </summary>
/// <param name="key"></param>
/// <param name="count"></param>
/// <returns></returns>
public long DecrBy(string key, int count)
{
return base.iClient.DecrementValueBy(key, count);
}
#endregion
}
}

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> <Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="..\packages\Microsoft.Extensions.Configuration.UserSecrets.2.2.0\build\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.props" Condition="Exists('..\packages\Microsoft.Extensions.Configuration.UserSecrets.2.2.0\build\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.props')" />
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" /> <Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup> <PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
@ -13,6 +14,8 @@
<ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> <ProjectTypeGuids>{60dc8134-eba5-43b8-bcc9-bb4bc16c2548};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
<Deterministic>true</Deterministic> <Deterministic>true</Deterministic>
<NuGetPackageImportStamp>
</NuGetPackageImportStamp>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols> <DebugSymbols>true</DebugSymbols>
@ -31,6 +34,42 @@
<ErrorReport>prompt</ErrorReport> <ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel> <WarningLevel>4</WarningLevel>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x86\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'">
<OutputPath>bin\x86\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x86</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'">
<DebugSymbols>true</DebugSymbols>
<OutputPath>bin\x64\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<DebugType>full</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'">
<OutputPath>bin\x64\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<Optimize>true</Optimize>
<DebugType>pdbonly</DebugType>
<PlatformTarget>x64</PlatformTarget>
<LangVersion>7.3</LangVersion>
<ErrorReport>prompt</ErrorReport>
</PropertyGroup>
<ItemGroup> <ItemGroup>
<Reference Include="Arction.DirectX, Version=10.4.1.4001, Culture=neutral, PublicKeyToken=6484d7bb14b95dd3, processorArchitecture=MSIL"> <Reference Include="Arction.DirectX, Version=10.4.1.4001, Culture=neutral, PublicKeyToken=6484d7bb14b95dd3, processorArchitecture=MSIL">
<SpecificVersion>False</SpecificVersion> <SpecificVersion>False</SpecificVersion>
@ -71,6 +110,96 @@
<Reference Include="DryIoc, Version=4.7.7.0, Culture=neutral, PublicKeyToken=dfbf2bd50fcf7768, processorArchitecture=MSIL"> <Reference Include="DryIoc, Version=4.7.7.0, Culture=neutral, PublicKeyToken=dfbf2bd50fcf7768, processorArchitecture=MSIL">
<HintPath>..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll</HintPath> <HintPath>..\packages\DryIoc.dll.4.7.7\lib\net45\DryIoc.dll</HintPath>
</Reference> </Reference>
<Reference Include="Microsoft.AspNetCore.Cryptography.Internal, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Cryptography.Internal.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Cryptography.Internal.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Cryptography.KeyDerivation, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Cryptography.KeyDerivation.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Cryptography.KeyDerivation.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Hosting, Version=2.2.7.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Hosting.2.2.7\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Hosting.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Hosting.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Hosting.Server.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Hosting.Server.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Hosting.Server.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Http, Version=2.2.2.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Http.2.2.2\lib\netstandard2.0\Microsoft.AspNetCore.Http.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Http.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Http.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Http.Extensions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Http.Extensions.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Extensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.Http.Features, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.Http.Features.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.Http.Features.dll</HintPath>
</Reference>
<Reference Include="Microsoft.AspNetCore.WebUtilities, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.AspNetCore.WebUtilities.2.2.0\lib\netstandard2.0\Microsoft.AspNetCore.WebUtilities.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Bcl.AsyncInterfaces, Version=5.0.0.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Bcl.AsyncInterfaces.5.0.0\lib\net461\Microsoft.Bcl.AsyncInterfaces.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.Binder, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.Binder.2.2.4\lib\netstandard2.0\Microsoft.Extensions.Configuration.Binder.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.EnvironmentVariables, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.EnvironmentVariables.2.2.4\lib\netstandard2.0\Microsoft.Extensions.Configuration.EnvironmentVariables.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.FileExtensions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.FileExtensions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.FileExtensions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.Json, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.Json.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.Json.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Configuration.UserSecrets, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Configuration.UserSecrets.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.2.2.0\lib\net461\Microsoft.Extensions.DependencyInjection.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.DependencyInjection.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.DependencyInjection.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.DependencyInjection.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.FileProviders.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.FileProviders.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.FileProviders.Physical, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.FileProviders.Physical.2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileProviders.Physical.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.FileSystemGlobbing, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.FileSystemGlobbing.2.2.0\lib\netstandard2.0\Microsoft.Extensions.FileSystemGlobbing.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Hosting.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Hosting.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Hosting.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Logging.Abstractions, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Logging.Abstractions.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Logging.Abstractions.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.ObjectPool, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.ObjectPool.2.2.0\lib\netstandard2.0\Microsoft.Extensions.ObjectPool.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Options, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Options.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Options.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Extensions.Primitives, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Extensions.Primitives.2.2.0\lib\netstandard2.0\Microsoft.Extensions.Primitives.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Net.Http.Headers, Version=2.2.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Net.Http.Headers.2.2.0\lib\netstandard2.0\Microsoft.Net.Http.Headers.dll</HintPath>
</Reference>
<Reference Include="Microsoft.Xaml.Behaviors, Version=1.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL"> <Reference Include="Microsoft.Xaml.Behaviors, Version=1.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\Microsoft.Xaml.Behaviors.Wpf.1.1.31\lib\net45\Microsoft.Xaml.Behaviors.dll</HintPath> <HintPath>..\packages\Microsoft.Xaml.Behaviors.Wpf.1.1.31\lib\net45\Microsoft.Xaml.Behaviors.dll</HintPath>
</Reference> </Reference>
@ -86,12 +215,143 @@
<Reference Include="Prism.Wpf, Version=8.1.97.5141, Culture=neutral, PublicKeyToken=40ee6c3a2184dc59, processorArchitecture=MSIL"> <Reference Include="Prism.Wpf, Version=8.1.97.5141, Culture=neutral, PublicKeyToken=40ee6c3a2184dc59, processorArchitecture=MSIL">
<HintPath>..\packages\Prism.Wpf.8.1.97\lib\net461\Prism.Wpf.dll</HintPath> <HintPath>..\packages\Prism.Wpf.8.1.97\lib\net461\Prism.Wpf.dll</HintPath>
</Reference> </Reference>
<Reference Include="ServiceStack, Version=6.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ServiceStack.6.0.2\lib\netstandard2.0\ServiceStack.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.Client, Version=6.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ServiceStack.Client.6.0.2\lib\netstandard2.0\ServiceStack.Client.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.Common, Version=6.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ServiceStack.Common.6.0.2\lib\netstandard2.0\ServiceStack.Common.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.Interfaces, Version=6.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ServiceStack.Interfaces.6.0.2\lib\netstandard2.0\ServiceStack.Interfaces.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.Redis, Version=6.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ServiceStack.Redis.6.0.2\lib\netstandard2.0\ServiceStack.Redis.dll</HintPath>
</Reference>
<Reference Include="ServiceStack.Text, Version=6.0.0.0, Culture=neutral, processorArchitecture=MSIL">
<HintPath>..\packages\ServiceStack.Text.6.0.2\lib\netstandard2.0\ServiceStack.Text.dll</HintPath>
</Reference>
<Reference Include="System" /> <Reference Include="System" />
<Reference Include="System.Buffers, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Buffers.4.5.1\lib\net461\System.Buffers.dll</HintPath>
</Reference>
<Reference Include="System.Collections.Immutable, Version=1.2.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Collections.Immutable.1.5.0\lib\netstandard2.0\System.Collections.Immutable.dll</HintPath>
</Reference>
<Reference Include="System.Collections.NonGeneric, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Collections.NonGeneric.4.3.0\lib\net46\System.Collections.NonGeneric.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Collections.Specialized, Version=4.0.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Collections.Specialized.4.3.0\lib\net46\System.Collections.Specialized.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.ComponentModel.Annotations, Version=4.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.ComponentModel.Annotations.5.0.0\lib\net461\System.ComponentModel.Annotations.dll</HintPath>
</Reference>
<Reference Include="System.ComponentModel.Composition" />
<Reference Include="System.ComponentModel.DataAnnotations" />
<Reference Include="System.ComponentModel.Primitives, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.ComponentModel.Primitives.4.3.0\lib\net45\System.ComponentModel.Primitives.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Configuration" /> <Reference Include="System.Configuration" />
<Reference Include="System.Data" /> <Reference Include="System.Data" />
<Reference Include="System.Data.Common, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Data.Common.4.3.0\lib\net451\System.Data.Common.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Diagnostics.DiagnosticSource, Version=4.0.3.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Diagnostics.DiagnosticSource.4.5.1\lib\net46\System.Diagnostics.DiagnosticSource.dll</HintPath>
</Reference>
<Reference Include="System.Drawing" />
<Reference Include="System.Drawing.Common, Version=4.0.0.2, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Drawing.Common.5.0.2\lib\net461\System.Drawing.Common.dll</HintPath>
</Reference>
<Reference Include="System.IdentityModel" />
<Reference Include="System.Memory, Version=4.0.1.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Memory.4.5.4\lib\net461\System.Memory.dll</HintPath>
</Reference>
<Reference Include="System.Net" />
<Reference Include="System.Net.NameResolution, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.NameResolution.4.3.0\lib\net46\System.Net.NameResolution.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.NetworkInformation, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.NetworkInformation.4.3.0\lib\net46\System.Net.NetworkInformation.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Net.Security, Version=4.0.1.2, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Net.Security.4.3.2\lib\net46\System.Net.Security.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Numerics" />
<Reference Include="System.Numerics.Vectors, Version=4.1.4.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Numerics.Vectors.4.5.0\lib\net46\System.Numerics.Vectors.dll</HintPath>
</Reference>
<Reference Include="System.Reflection.Metadata, Version=1.4.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reflection.Metadata.1.6.0\lib\netstandard2.0\System.Reflection.Metadata.dll</HintPath>
</Reference>
<Reference Include="System.Reflection.TypeExtensions, Version=4.1.5.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Reflection.TypeExtensions.4.7.0\lib\net461\System.Reflection.TypeExtensions.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.CompilerServices.Unsafe, Version=4.0.4.1, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.CompilerServices.Unsafe.4.5.3\lib\net461\System.Runtime.CompilerServices.Unsafe.dll</HintPath>
</Reference>
<Reference Include="System.Runtime.Serialization" />
<Reference Include="System.Runtime.Serialization.Primitives, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Runtime.Serialization.Primitives.4.3.0\lib\net46\System.Runtime.Serialization.Primitives.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Cryptography.Algorithms, Version=4.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Algorithms.4.3.0\lib\net461\System.Security.Cryptography.Algorithms.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Cryptography.Encoding, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Encoding.4.3.0\lib\net46\System.Security.Cryptography.Encoding.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Cryptography.Primitives, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.Primitives.4.3.0\lib\net46\System.Security.Cryptography.Primitives.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.Security.Cryptography.X509Certificates, Version=4.1.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Security.Cryptography.X509Certificates.4.3.0\lib\net461\System.Security.Cryptography.X509Certificates.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.ServiceModel" />
<Reference Include="System.ServiceModel.Primitives, Version=4.8.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.ServiceModel.Primitives.4.8.1\lib\net461\System.ServiceModel.Primitives.dll</HintPath>
</Reference>
<Reference Include="System.Text.Encodings.Web, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Text.Encodings.Web.4.5.0\lib\netstandard2.0\System.Text.Encodings.Web.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Tasks.Extensions, Version=4.2.0.1, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Tasks.Extensions.4.5.4\lib\net461\System.Threading.Tasks.Extensions.dll</HintPath>
</Reference>
<Reference Include="System.Threading.Thread, Version=4.0.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<HintPath>..\packages\System.Threading.Thread.4.3.0\lib\net46\System.Threading.Thread.dll</HintPath>
<Private>True</Private>
<Private>True</Private>
</Reference>
<Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL"> <Reference Include="System.ValueTuple, Version=4.0.3.0, Culture=neutral, PublicKeyToken=cc7b13ffcd2ddd51, processorArchitecture=MSIL">
<HintPath>..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath> <HintPath>..\packages\System.ValueTuple.4.5.0\lib\net461\System.ValueTuple.dll</HintPath>
</Reference> </Reference>
<Reference Include="System.Web" />
<Reference Include="System.Xml" /> <Reference Include="System.Xml" />
<Reference Include="Microsoft.CSharp" /> <Reference Include="Microsoft.CSharp" />
<Reference Include="System.Core" /> <Reference Include="System.Core" />
@ -107,6 +367,10 @@
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Compile Include="Bool2VisibilityConverter.cs" /> <Compile Include="Bool2VisibilityConverter.cs" />
<Compile Include="Init\RedisConfigInfo.cs" />
<Compile Include="Init\RedisManager.cs" />
<Compile Include="Interface\RedisBase.cs" />
<Compile Include="Mseed2asciiApi.cs" />
<Compile Include="MseedChartModule.cs" /> <Compile Include="MseedChartModule.cs" />
<Compile Include="Models\CoordBase.cs" /> <Compile Include="Models\CoordBase.cs" />
<Compile Include="Models\LineDatas.cs" /> <Compile Include="Models\LineDatas.cs" />
@ -128,7 +392,13 @@
<DesignTimeSharedInput>True</DesignTimeSharedInput> <DesignTimeSharedInput>True</DesignTimeSharedInput>
</Compile> </Compile>
<Compile Include="RegionNames.cs" /> <Compile Include="RegionNames.cs" />
<Compile Include="Service\RedisListService.cs" />
<Compile Include="Service\RedisStringService.cs" />
<Compile Include="ViewModels\ChartPlotRealDataViewModel.cs" />
<Compile Include="ViewModels\ChartPlotViewModel.cs" /> <Compile Include="ViewModels\ChartPlotViewModel.cs" />
<Compile Include="Views\ChartPlotRealDataView.xaml.cs">
<DependentUpon>ChartPlotRealDataView.xaml</DependentUpon>
</Compile>
<Compile Include="Views\ChartPlotView.xaml.cs"> <Compile Include="Views\ChartPlotView.xaml.cs">
<DependentUpon>ChartPlotView.xaml</DependentUpon> <DependentUpon>ChartPlotView.xaml</DependentUpon>
</Compile> </Compile>
@ -136,6 +406,7 @@
<Generator>ResXFileCodeGenerator</Generator> <Generator>ResXFileCodeGenerator</Generator>
<LastGenOutput>Resources.Designer.cs</LastGenOutput> <LastGenOutput>Resources.Designer.cs</LastGenOutput>
</EmbeddedResource> </EmbeddedResource>
<None Include="app.config" />
<None Include="packages.config" /> <None Include="packages.config" />
<None Include="Properties\Settings.settings"> <None Include="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator> <Generator>SettingsSingleFileGenerator</Generator>
@ -143,6 +414,10 @@
</None> </None>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Page Include="Views\ChartPlotRealDataView.xaml">
<Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType>
</Page>
<Page Include="Views\ChartPlotView.xaml"> <Page Include="Views\ChartPlotView.xaml">
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
<SubType>Designer</SubType> <SubType>Designer</SubType>
@ -155,4 +430,12 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">
<PropertyGroup>
<ErrorText>这台计算机上缺少此项目引用的 NuGet 程序包。使用“NuGet 程序包还原”可下载这些程序包。有关更多信息,请参见 http://go.microsoft.com/fwlink/?LinkID=322105。缺少的文件是 {0}。</ErrorText>
</PropertyGroup>
<Error Condition="!Exists('..\packages\Microsoft.Extensions.Configuration.UserSecrets.2.2.0\build\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.props')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Extensions.Configuration.UserSecrets.2.2.0\build\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.props'))" />
<Error Condition="!Exists('..\packages\Microsoft.Extensions.Configuration.UserSecrets.2.2.0\build\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.targets')" Text="$([System.String]::Format('$(ErrorText)', '..\packages\Microsoft.Extensions.Configuration.UserSecrets.2.2.0\build\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.targets'))" />
</Target>
<Import Project="..\packages\Microsoft.Extensions.Configuration.UserSecrets.2.2.0\build\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.targets" Condition="Exists('..\packages\Microsoft.Extensions.Configuration.UserSecrets.2.2.0\build\netstandard2.0\Microsoft.Extensions.Configuration.UserSecrets.targets')" />
</Project> </Project>

@ -33,6 +33,7 @@ using System.Windows.Media.Imaging;
using System.Windows.Threading; using System.Windows.Threading;
using System.Xml.Linq; using System.Xml.Linq;
using Prism.Regions; using Prism.Regions;
using static System.Collections.Specialized.BitVector32;
namespace StartServerWPF.Modules.MseedChart.ViewModels namespace StartServerWPF.Modules.MseedChart.ViewModels
{ {
@ -463,15 +464,24 @@ namespace StartServerWPF.Modules.MseedChart.ViewModels
private void RealTimeData(object isCheck) private void RealTimeData(object isCheck)
{ {
//
String str = "N02,N03,N04,N05,N06";//,N07,N08,N09,N10,N11,N12,N13,N14,N15,N16,N17,N18,N19,N20,N21,N22,N23,N24,N25,N26,N27";
var stations= str.Split(',');
smList = _wavesModel.ReadWavesFromJson(stations);
_channelCount = smList.Count * 3;
CurrentTime = smList.First().BeginTime.ToShortDateString();
StationsName = smList.Select(a => new StationAxis { Name = a.Name, IsChecked = true, SelectCommand = new DelegateCommand<object>(StationsNameVisible) }).ToList();
// StartChart();
if (_lChartAll != null) if (_lChartAll != null)
{ {
bool yAxesVisible = ((bool)isCheck == true); bool isStartRealData = (Convert.ToBoolean(isCheck) == true);
if (smList.Count == 0) if (smList.Count == 0)
{ {
return; return;
} }
_lChartAll.BeginUpdate(); _lChartAll.BeginUpdate();
if (yAxesVisible) if (isStartRealData)
{ {
StartChart(); StartChart();
//Set real-time monitoring automatic old data destruction //Set real-time monitoring automatic old data destruction

@ -0,0 +1,61 @@
<UserControl x:Class="StartServerWPF.Modules.MseedChart.Views.ChartPlotRealDataView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:converter="clr-namespace:StartServerWPF.Modules.MseedChart.Converters"
mc:Ignorable="d" Background="#FFEEF1F3"
xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
d:DesignHeight="450" d:DesignWidth="800"
xmlns:prism="http://prismlibrary.com/"
prism:ViewModelLocator.AutoWireViewModel="True">
<UserControl.Resources>
<converter:Bool2VisibilityConverter x:Key="Bool2Visibility"/>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition Height="50"/>
<RowDefinition Height="1000*"/>
</Grid.RowDefinitions>
<i:Interaction.Triggers>
<i:EventTrigger EventName="Loaded">
<i:InvokeCommandAction Command="{Binding Path=LoadedCommand}"/>
</i:EventTrigger>
<i:EventTrigger EventName="Unloaded">
<i:InvokeCommandAction Command="{Binding Path=UnloadedCommand}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<Border Background="White">
<TextBlock Text="{Binding Title}" FontSize="16" FontWeight="Bold" VerticalAlignment="Center" Margin="10,0,10,0"/>
</Border>
<Border Background="White" Grid.Row="1" Grid.RowSpan="2" CornerRadius="5" Margin="10">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="1000*"/>
</Grid.RowDefinitions>
<!--实时波形-->
<StackPanel Orientation="Horizontal" Visibility="{Binding IsRealtimeData,Converter={StaticResource Bool2Visibility}}" Background="White">
<Button Grid.Column="1" Grid.Row="1" Command="{Binding RealTimeDataCommand}" CommandParameter="true" Background="#FF3BB4FF" >开始接收</Button>
<Button Grid.Column="1" Grid.Row="1" Command="{Binding RealTimeDataCommand}" CommandParameter="false" Background="#FFFFAF20" Margin="20,0,20,0">停止接收</Button>
<CheckBox Content="通道选择" x:Name="cBoxAllChannel" IsChecked="{Binding SingleChannel}" VerticalAlignment="Center"/>
<ComboBox IsEnabled="{Binding ElementName=cBoxAllChannel, Path=IsChecked}" Text="{Binding SelectChannel}" SelectedIndex="0" VerticalAlignment="Center">
<ComboBoxItem Content="SHZ"/>
<ComboBoxItem Content="SHN"/>
<ComboBoxItem Content="SHE"/>
</ComboBox>
<TextBlock VerticalAlignment="Center" Margin="20,0,0,0">时间间隔:</TextBlock>
<TextBox Text="{Binding XaisInterval}" Width="60" VerticalAlignment="Center"/>
<Button Command="{Binding IntervalSureCommand}" Background="#FF66B1FF" HorizontalAlignment="Right">确认</Button>
<CheckBox Command="{Binding AxesYVisibleCommand}" Visibility="Collapsed" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=IsChecked}" Content="Y轴显示" VerticalContentAlignment="Center" IsChecked="True" FontSize="15" Foreground="Black" Margin="5,0,5,0" FontWeight="Bold" />
<CheckBox Command="{Binding RealTimeDataCommand}" CommandParameter="{Binding RelativeSource={RelativeSource Mode=Self},Path=IsChecked}" Visibility="Collapsed" Content="实时" VerticalContentAlignment="Center" FontSize="15" Foreground="Black" FontWeight="Bold" DockPanel.Dock="Right"></CheckBox>
<TextBox Text="{Binding IntervalTime}" Visibility="Collapsed" Width="60" VerticalAlignment="Center"></TextBox>
<!--<TextBox Text="{Binding IntervalTime}" Width="60" VerticalAlignment="Center"></TextBox>-->
</StackPanel>
<ContentControl x:Name="contentControl" Content="{Binding ChildContent}" Grid.Row="1"/>
<TextBlock Text="{Binding CurrentTime}" Grid.Row="1" VerticalAlignment="Bottom" HorizontalAlignment="Left" Margin="0,0,0,46"></TextBlock>
</Grid>
</Border>
</Grid>
</UserControl>

@ -0,0 +1,29 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace StartServerWPF.Modules.MseedChart.Views
{
/// <summary>
/// Interaction logic for ViewA.xaml
/// </summary>
public partial class ChartPlotRealDataView : UserControl
{
public ChartPlotRealDataView()
{
InitializeComponent();
}
}
}

@ -66,7 +66,7 @@
<!--实时波形--> <!--实时波形-->
<StackPanel Orientation="Horizontal" Visibility="{Binding IsRealtimeData,Converter={StaticResource Bool2Visibility}}" Background="White"> <StackPanel Orientation="Horizontal" Visibility="{Binding IsRealtimeData,Converter={StaticResource Bool2Visibility}}" Background="White">
<Button Grid.Column="1" Grid.Row="1" Command="{Binding RealTimeDataCommand}" CommandParameter="true" Background="#FF3BB4FF" >开始接收</Button> <Button Grid.Column="1" Grid.Row="1" Command="{Binding RealTimeDataCommand}" CommandParameter="true" Background="#FF3BB4FF" >开始接收</Button>
<Button Grid.Column="1" Grid.Row="1" Command="{Binding FileSelectorCommand}" CommandParameter="false" Background="#FFFFAF20" Margin="20,0,20,0">停止接收</Button> <Button Grid.Column="1" Grid.Row="1" Command="{Binding RealTimeDataCommand}" CommandParameter="false" Background="#FFFFAF20" Margin="20,0,20,0">停止接收</Button>
<CheckBox Content="通道选择" x:Name="cBoxAllChannel" IsChecked="{Binding SingleChannel}" VerticalAlignment="Center"/> <CheckBox Content="通道选择" x:Name="cBoxAllChannel" IsChecked="{Binding SingleChannel}" VerticalAlignment="Center"/>
<ComboBox IsEnabled="{Binding ElementName=cBoxAllChannel, Path=IsChecked}" Text="{Binding SelectChannel}" SelectedIndex="0" VerticalAlignment="Center"> <ComboBox IsEnabled="{Binding ElementName=cBoxAllChannel, Path=IsChecked}" Text="{Binding SelectChannel}" SelectedIndex="0" VerticalAlignment="Center">
<ComboBoxItem Content="SHZ"/> <ComboBoxItem Content="SHZ"/>

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Memory" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.1.1" newVersion="4.0.1.1" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.4.1" newVersion="4.0.4.1" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-13.0.0.0" newVersion="13.0.0.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Microsoft.AspNetCore.Http" publicKeyToken="adb9793829ddae60" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-2.2.2.0" newVersion="2.2.2.0" />
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ComponentModel.Annotations" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.1.0" newVersion="4.2.1.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

@ -1,10 +1,79 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<packages> <packages>
<package id="DryIoc.dll" version="4.7.7" targetFramework="net461" /> <package id="DryIoc.dll" version="4.7.7" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Cryptography.Internal" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Cryptography.KeyDerivation" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Hosting" version="2.2.7" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Hosting.Abstractions" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Hosting.Server.Abstractions" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Http" version="2.2.2" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Http.Abstractions" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Http.Extensions" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.AspNetCore.Http.Features" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.AspNetCore.WebUtilities" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Bcl.AsyncInterfaces" version="5.0.0" targetFramework="net461" />
<package id="Microsoft.CSharp" version="4.7.0" targetFramework="net461" />
<package id="Microsoft.Extensions.Configuration" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.Configuration.Abstractions" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.Configuration.Binder" version="2.2.4" targetFramework="net461" />
<package id="Microsoft.Extensions.Configuration.EnvironmentVariables" version="2.2.4" targetFramework="net461" />
<package id="Microsoft.Extensions.Configuration.FileExtensions" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.Configuration.Json" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.Configuration.UserSecrets" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.DependencyInjection" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.DependencyInjection.Abstractions" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.FileProviders.Abstractions" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.FileProviders.Physical" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.FileSystemGlobbing" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.Hosting.Abstractions" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.Logging" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.Logging.Abstractions" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.ObjectPool" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.Options" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Extensions.Primitives" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Net.Http.Headers" version="2.2.0" targetFramework="net461" />
<package id="Microsoft.Xaml.Behaviors.Wpf" version="1.1.31" targetFramework="net461" /> <package id="Microsoft.Xaml.Behaviors.Wpf" version="1.1.31" targetFramework="net461" />
<package id="Newtonsoft.Json" version="13.0.3" targetFramework="net461" /> <package id="Newtonsoft.Json" version="13.0.3" targetFramework="net461" />
<package id="Prism.Core" version="8.1.97" targetFramework="net461" /> <package id="Prism.Core" version="8.1.97" targetFramework="net461" />
<package id="Prism.DryIoc" version="8.1.97" targetFramework="net461" /> <package id="Prism.DryIoc" version="8.1.97" targetFramework="net461" />
<package id="Prism.Wpf" version="8.1.97" targetFramework="net461" /> <package id="Prism.Wpf" version="8.1.97" targetFramework="net461" />
<package id="ServiceStack" version="6.0.2" targetFramework="net461" />
<package id="ServiceStack.Client" version="6.0.2" targetFramework="net461" />
<package id="ServiceStack.Common" version="6.0.2" targetFramework="net461" />
<package id="ServiceStack.Interfaces" version="6.0.2" targetFramework="net461" />
<package id="ServiceStack.Redis" version="6.0.2" targetFramework="net461" />
<package id="ServiceStack.Text" version="6.0.2" targetFramework="net461" />
<package id="System.Buffers" version="4.5.1" targetFramework="net461" />
<package id="System.Collections.Immutable" version="1.5.0" targetFramework="net461" />
<package id="System.Collections.NonGeneric" version="4.3.0" targetFramework="net461" />
<package id="System.Collections.Specialized" version="4.3.0" targetFramework="net461" />
<package id="System.ComponentModel.Annotations" version="5.0.0" targetFramework="net461" />
<package id="System.ComponentModel.Primitives" version="4.3.0" targetFramework="net461" />
<package id="System.Data.Common" version="4.3.0" targetFramework="net461" />
<package id="System.Diagnostics.DiagnosticSource" version="4.5.1" targetFramework="net461" />
<package id="System.Drawing.Common" version="5.0.2" targetFramework="net461" />
<package id="System.Dynamic.Runtime" version="4.3.0" targetFramework="net461" />
<package id="System.Linq.Queryable" version="4.3.0" targetFramework="net461" />
<package id="System.Memory" version="4.5.4" targetFramework="net461" />
<package id="System.Net.NameResolution" version="4.3.0" targetFramework="net461" />
<package id="System.Net.NetworkInformation" version="4.3.0" targetFramework="net461" />
<package id="System.Net.Requests" version="4.3.0" targetFramework="net461" />
<package id="System.Net.Security" version="4.3.2" targetFramework="net461" />
<package id="System.Numerics.Vectors" version="4.5.0" targetFramework="net461" />
<package id="System.Reflection.Emit" version="4.7.0" targetFramework="net461" />
<package id="System.Reflection.Metadata" version="1.6.0" targetFramework="net461" />
<package id="System.Reflection.TypeExtensions" version="4.7.0" targetFramework="net461" />
<package id="System.Runtime" version="4.3.1" targetFramework="net461" />
<package id="System.Runtime.CompilerServices.Unsafe" version="4.5.3" targetFramework="net461" />
<package id="System.Runtime.Serialization.Primitives" version="4.3.0" targetFramework="net461" />
<package id="System.Security.Cryptography.Algorithms" version="4.3.0" targetFramework="net461" />
<package id="System.Security.Cryptography.Encoding" version="4.3.0" targetFramework="net461" />
<package id="System.Security.Cryptography.Primitives" version="4.3.0" targetFramework="net461" />
<package id="System.Security.Cryptography.X509Certificates" version="4.3.0" targetFramework="net461" />
<package id="System.ServiceModel.Primitives" version="4.8.1" targetFramework="net461" />
<package id="System.Text.Encodings.Web" version="4.5.0" targetFramework="net461" />
<package id="System.Threading.Tasks.Extensions" version="4.5.4" targetFramework="net461" />
<package id="System.Threading.Thread" version="4.3.0" targetFramework="net461" />
<package id="System.ValueTuple" version="4.5.0" targetFramework="net461" /> <package id="System.ValueTuple" version="4.5.0" targetFramework="net461" />
<package id="System.Xml.XmlSerializer" version="4.3.0" targetFramework="net461" />
</packages> </packages>

@ -3,36 +3,86 @@ Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17 # Visual Studio Version 17
VisualStudioVersion = 17.3.32819.101 VisualStudioVersion = 17.3.32819.101
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StartServerWPF.Modules.Main", "StartServerWPF.Modules.Main\StartServerWPF.Modules.Main.csproj", "{D9A5C84C-296A-458E-9CCB-BCD95959F88B}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StartServerWPF", "StartServerWPF\StartServerWPF.csproj", "{7585A28B-9A36-4B10-9033-0214C93F68F5}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "StartServerWPF", "StartServerWPF\StartServerWPF.csproj", "{7585A28B-9A36-4B10-9033-0214C93F68F5}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StartServerWPF.Modules.MseedChart", "StartServerWPF.Modules.MseedChart\StartServerWPF.Modules.MseedChart.csproj", "{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StartServerWPF.Modules.MseedChart", "StartServerWPF.Modules.MseedChart\StartServerWPF.Modules.MseedChart.csproj", "{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}"
EndProject EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StartServerWPF.Assets", "StartServerWPF.Assets\StartServerWPF.Assets.csproj", "{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}" Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StartServerWPF.Assets", "StartServerWPF.Assets\StartServerWPF.Assets.csproj", "{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}"
EndProject EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mseedC", "mseedC\mseedC.vcxproj", "{69F6D457-8FC8-440D-B390-8D7D76D88C05}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "StartServerWPF.Modules.Main", "Modules\StartServerWPF.Modules.Main\StartServerWPF.Modules.Main.csproj", "{9A6AF364-195E-4017-9CF8-D3E59928D124}"
EndProject
Global Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64
Debug|x86 = Debug|x86
Release|Any CPU = Release|Any CPU Release|Any CPU = Release|Any CPU
Release|x64 = Release|x64
Release|x86 = Release|x86
EndGlobalSection EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution GlobalSection(ProjectConfigurationPlatforms) = postSolution
{D9A5C84C-296A-458E-9CCB-BCD95959F88B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{D9A5C84C-296A-458E-9CCB-BCD95959F88B}.Debug|Any CPU.Build.0 = Debug|Any CPU
{D9A5C84C-296A-458E-9CCB-BCD95959F88B}.Release|Any CPU.ActiveCfg = Release|Any CPU
{D9A5C84C-296A-458E-9CCB-BCD95959F88B}.Release|Any CPU.Build.0 = Release|Any CPU
{7585A28B-9A36-4B10-9033-0214C93F68F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {7585A28B-9A36-4B10-9033-0214C93F68F5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{7585A28B-9A36-4B10-9033-0214C93F68F5}.Debug|Any CPU.Build.0 = Debug|Any CPU {7585A28B-9A36-4B10-9033-0214C93F68F5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{7585A28B-9A36-4B10-9033-0214C93F68F5}.Debug|x64.ActiveCfg = Debug|x64
{7585A28B-9A36-4B10-9033-0214C93F68F5}.Debug|x64.Build.0 = Debug|x64
{7585A28B-9A36-4B10-9033-0214C93F68F5}.Debug|x86.ActiveCfg = Debug|x86
{7585A28B-9A36-4B10-9033-0214C93F68F5}.Debug|x86.Build.0 = Debug|x86
{7585A28B-9A36-4B10-9033-0214C93F68F5}.Release|Any CPU.ActiveCfg = Release|Any CPU {7585A28B-9A36-4B10-9033-0214C93F68F5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{7585A28B-9A36-4B10-9033-0214C93F68F5}.Release|Any CPU.Build.0 = Release|Any CPU {7585A28B-9A36-4B10-9033-0214C93F68F5}.Release|Any CPU.Build.0 = Release|Any CPU
{7585A28B-9A36-4B10-9033-0214C93F68F5}.Release|x64.ActiveCfg = Release|x64
{7585A28B-9A36-4B10-9033-0214C93F68F5}.Release|x64.Build.0 = Release|x64
{7585A28B-9A36-4B10-9033-0214C93F68F5}.Release|x86.ActiveCfg = Release|x86
{7585A28B-9A36-4B10-9033-0214C93F68F5}.Release|x86.Build.0 = Release|x86
{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Debug|Any CPU.Build.0 = Debug|Any CPU {E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Debug|Any CPU.Build.0 = Debug|Any CPU
{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Debug|x64.ActiveCfg = Debug|x64
{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Debug|x64.Build.0 = Debug|x64
{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Debug|x86.ActiveCfg = Debug|x86
{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Debug|x86.Build.0 = Debug|x86
{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Release|Any CPU.ActiveCfg = Release|Any CPU {E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Release|Any CPU.ActiveCfg = Release|Any CPU
{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Release|Any CPU.Build.0 = Release|Any CPU {E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Release|Any CPU.Build.0 = Release|Any CPU
{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Release|x64.ActiveCfg = Release|x64
{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Release|x64.Build.0 = Release|x64
{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Release|x86.ActiveCfg = Release|x86
{E0B8EEB4-E63B-488C-BEAD-F03D488CDCB6}.Release|x86.Build.0 = Release|x86
{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Debug|Any CPU.Build.0 = Debug|Any CPU {EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Debug|x64.ActiveCfg = Debug|x64
{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Debug|x64.Build.0 = Debug|x64
{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Debug|x86.ActiveCfg = Debug|x86
{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Debug|x86.Build.0 = Debug|x86
{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Release|Any CPU.ActiveCfg = Release|Any CPU {EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Release|Any CPU.Build.0 = Release|Any CPU {EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Release|Any CPU.Build.0 = Release|Any CPU
{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Release|x64.ActiveCfg = Release|x64
{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Release|x64.Build.0 = Release|x64
{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Release|x86.ActiveCfg = Release|x86
{EA0D3C2D-5BEB-420C-9222-2E6E5F40BF5C}.Release|x86.Build.0 = Release|x86
{69F6D457-8FC8-440D-B390-8D7D76D88C05}.Debug|Any CPU.ActiveCfg = Debug|x64
{69F6D457-8FC8-440D-B390-8D7D76D88C05}.Debug|Any CPU.Build.0 = Debug|x64
{69F6D457-8FC8-440D-B390-8D7D76D88C05}.Debug|x64.ActiveCfg = Debug|x64
{69F6D457-8FC8-440D-B390-8D7D76D88C05}.Debug|x64.Build.0 = Debug|x64
{69F6D457-8FC8-440D-B390-8D7D76D88C05}.Debug|x86.ActiveCfg = Debug|Win32
{69F6D457-8FC8-440D-B390-8D7D76D88C05}.Debug|x86.Build.0 = Debug|Win32
{69F6D457-8FC8-440D-B390-8D7D76D88C05}.Release|Any CPU.ActiveCfg = Release|x64
{69F6D457-8FC8-440D-B390-8D7D76D88C05}.Release|Any CPU.Build.0 = Release|x64
{69F6D457-8FC8-440D-B390-8D7D76D88C05}.Release|x64.ActiveCfg = Release|x64
{69F6D457-8FC8-440D-B390-8D7D76D88C05}.Release|x64.Build.0 = Release|x64
{69F6D457-8FC8-440D-B390-8D7D76D88C05}.Release|x86.ActiveCfg = Release|Win32
{69F6D457-8FC8-440D-B390-8D7D76D88C05}.Release|x86.Build.0 = Release|Win32
{9A6AF364-195E-4017-9CF8-D3E59928D124}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{9A6AF364-195E-4017-9CF8-D3E59928D124}.Debug|Any CPU.Build.0 = Debug|Any CPU
{9A6AF364-195E-4017-9CF8-D3E59928D124}.Debug|x64.ActiveCfg = Debug|x64
{9A6AF364-195E-4017-9CF8-D3E59928D124}.Debug|x64.Build.0 = Debug|x64
{9A6AF364-195E-4017-9CF8-D3E59928D124}.Debug|x86.ActiveCfg = Debug|Any CPU
{9A6AF364-195E-4017-9CF8-D3E59928D124}.Debug|x86.Build.0 = Debug|Any CPU
{9A6AF364-195E-4017-9CF8-D3E59928D124}.Release|Any CPU.ActiveCfg = Release|Any CPU
{9A6AF364-195E-4017-9CF8-D3E59928D124}.Release|Any CPU.Build.0 = Release|Any CPU
{9A6AF364-195E-4017-9CF8-D3E59928D124}.Release|x64.ActiveCfg = Release|Any CPU
{9A6AF364-195E-4017-9CF8-D3E59928D124}.Release|x64.Build.0 = Release|Any CPU
{9A6AF364-195E-4017-9CF8-D3E59928D124}.Release|x86.ActiveCfg = Release|Any CPU
{9A6AF364-195E-4017-9CF8-D3E59928D124}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection EndGlobalSection
GlobalSection(SolutionProperties) = preSolution GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE HideSolutionNode = FALSE

@ -1,5 +1,4 @@
using Microsoft.VisualBasic.Logging; using Prism.Ioc;
using Prism.Ioc;
using Prism.Modularity; using Prism.Modularity;
using StartServerWPF.Modules.Main; using StartServerWPF.Modules.Main;
using StartServerWPF.Views; using StartServerWPF.Views;

@ -3,19 +3,33 @@
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net6.0-windows</TargetFramework>
<UseWPF>true</UseWPF> <UseWPF>true</UseWPF>
<Platforms>AnyCPU;x86;x64</Platforms>
<AnalysisLevel>preview-all</AnalysisLevel>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>
<PackageReference Include="Prism.DryIoc" Version="8.1.97" /> <PackageReference Include="Prism.DryIoc" Version="8.1.97" />
<PackageReference Include="System.Text.Json" Version="7.0.3" />
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Modules\StartServerWPF.Modules.Main\StartServerWPF.Modules.Main.csproj" />
<ProjectReference Include="..\StartServerWPF.Assets\StartServerWPF.Assets.csproj" /> <ProjectReference Include="..\StartServerWPF.Assets\StartServerWPF.Assets.csproj" />
<ProjectReference Include="..\StartServerWPF.Modules.Main\StartServerWPF.Modules.Main.csproj" />
<ProjectReference Include="..\StartServerWPF.Modules.MseedChart\StartServerWPF.Modules.MseedChart.csproj" /> <ProjectReference Include="..\StartServerWPF.Modules.MseedChart\StartServerWPF.Modules.MseedChart.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Update="Properties\Settings.Designer.cs">
<DesignTimeSharedInput>True</DesignTimeSharedInput>
<AutoGen>True</AutoGen>
<DependentUpon>Settings.settings</DependentUpon>
</Compile>
</ItemGroup>
<ItemGroup> <ItemGroup>
<None Update="mseed2ascii.exe"> <None Update="mseed2ascii.exe">
<CopyToOutputDirectory>Always</CopyToOutputDirectory> <CopyToOutputDirectory>Always</CopyToOutputDirectory>
</None> </None>
<None Update="Properties\Settings.settings">
<Generator>SettingsSingleFileGenerator</Generator>
<LastGenOutput>Settings.Designer.cs</LastGenOutput>
</None>
<None Update="SystemConfig.json"> <None Update="SystemConfig.json">
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory> <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
</None> </None>

@ -1,5 +1,4 @@
using Microsoft.VisualBasic.ApplicationServices; using Prism.Commands;
using Prism.Commands;
using Prism.Ioc; using Prism.Ioc;
using Prism.Mvvm; using Prism.Mvvm;
using StartServerWPF.Assets; using StartServerWPF.Assets;

@ -1,5 +1,4 @@
using Org.BouncyCastle.Tls.Crypto; using Prism.Ioc;
using Prism.Ioc;
using Prism.Regions; using Prism.Regions;
using StartServerWPF.Modules.Main.ViewModels; using StartServerWPF.Modules.Main.ViewModels;
using System.Windows; using System.Windows;

@ -0,0 +1,6 @@
BasedOnStyle: LLVM
AlwaysBreakAfterDefinitionReturnType: TopLevel
SpaceBeforeParens: Always
BreakBeforeBraces: Allman
AlignConsecutiveAssignments: true
ColumnLimit: 0

@ -0,0 +1,2 @@
doc/working/
doc/gh-pages/

File diff suppressed because it is too large Load Diff

@ -0,0 +1,48 @@
The library requires that C99 integer types are available on the
target computer. Specifically the int8_t, int16_t, int32_t, int64_t
and their unsigned counterpart types.
## Unix, Linux, macOS
A simple `make` on most Unix-like systems should build the library.
The included Makefile should work for most Unix-like environments and
many make variants. It is known to work with GNU make, which, if not the
default, is sometimes installed as `gmake`.
The `CC`, `CFLAGS`, `LDFLAGS` and `CPPFLAGS` environment variables can be set
to control the build.
If the **LIBMSEED_URL** variable is defined during the build, the library will
be compiled with support for reading from URLs. Currently, this support requires
that [libcurl](https://curl.haxx.se/) be installed on the target system.
The simplest way to build the library with URL support is to include `-DLIMSEED_URL`
in the CFLAGS environment variable. Or invoking the build as such:
```
CFLAGS+=" -DLIBMSEED_URL" make
```
By default a statically linked version of the library is built: **libmseed.a**,
with an accompanying header **libmseed.h**.
With GCC, clang or compatible build tools it is possible to build a shared
library with `make shared`.
A simple install method for the shared library can be invoked with
`make install`. By default the installation destination is /usr/local.
The install destination may be specified using the **PREFIX** variable, for
example:
```
make install PREFIX=/path/to/install/
```
## Windows
On a Windows platform the library can be compiled by using the
NMake compatible Makefile.win (e.g. 'nmake -f Makefile.win').
The default target is a static library 'libmseed.lib'.
A libmseed.def file is included for use building and linking a DLL.

@ -0,0 +1,201 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

@ -0,0 +1,119 @@
# Build environment can be configured the following
# environment variables:
# CC : Specify the C compiler to use
# CFLAGS : Specify compiler options to use
# LDFLAGS : Specify linker options to use
# CPPFLAGS : Specify c-preprocessor options to use
# Extract version from libmseed.h, expected line should include LIBMSEED_VERSION "#.#.#"
MAJOR_VER = $(shell grep LIBMSEED_VERSION libmseed.h | grep -Eo '[0-9]+.[0-9]+.[0-9]+' | cut -d . -f 1)
FULL_VER = $(shell grep LIBMSEED_VERSION libmseed.h | grep -Eo '[0-9]+.[0-9]+.[0-9]+')
COMPAT_VER = $(MAJOR_VER).0.0
# Default settings for install target
PREFIX ?= /usr/local
EXEC_PREFIX ?= $(PREFIX)
LIBDIR ?= $(EXEC_PREFIX)/lib
INCLUDEDIR ?= $(PREFIX)/include
DATAROOTDIR ?= $(PREFIX)/share
DOCDIR ?= $(DATAROOTDIR)/doc/libmseed
MANDIR ?= $(DATAROOTDIR)/man
MAN3DIR ?= $(MANDIR)/man3
LIB_SRCS = fileutils.c genutils.c msio.c lookup.c yyjson.c msrutils.c \
extraheaders.c pack.c packdata.c tracelist.c gmtime64.c crc32c.c \
parseutils.c unpack.c unpackdata.c selection.c logging.c
LIB_OBJS = $(LIB_SRCS:.c=.o)
LIB_LOBJS = $(LIB_SRCS:.c=.lo)
LIB_NAME = libmseed
LIB_A = $(LIB_NAME).a
OS := $(shell uname -s)
# Build dynamic (.dylib) on macOS/Darwin, otherwise shared (.so)
ifeq ($(OS), Darwin)
LIB_SO_BASE = $(LIB_NAME).dylib
LIB_SO_MAJOR = $(LIB_NAME).$(MAJOR_VER).dylib
LIB_SO = $(LIB_NAME).$(FULL_VER).dylib
LIB_OPTS = -dynamiclib -compatibility_version $(COMPAT_VER) -current_version $(FULL_VER) -install_name $(LIB_SO)
else
LIB_SO_BASE = $(LIB_NAME).so
LIB_SO_MAJOR = $(LIB_NAME).so.$(MAJOR_VER)
LIB_SO = $(LIB_NAME).so.$(FULL_VER)
LIB_OPTS = -shared -Wl,--version-script=libmseed.map -Wl,-soname,$(LIB_SO_MAJOR)
endif
# Automatically configure LDFLAGS for URL support if requested and libcurl is available
# Test for LIBMSEED_URL in CFLAGS, then if curl-config is available, implying libcurl is available
ifneq (,$(findstring LIBMSEED_URL,$(CFLAGS)))
ifneq (,$(shell command -v curl-config;))
export LM_CURL_VERSION=$(shell curl-config --version)
export LDLIBS:=$(LDLIBS) $(shell curl-config --libs)
endif
endif
all: static
static: $(LIB_A)
shared dynamic: $(LIB_SO)
# Build static library
$(LIB_A): $(LIB_OBJS)
@echo "Building static library $(LIB_A)"
$(RM) -f $(LIB_A)
$(AR) -crs $(LIB_A) $(LIB_OBJS)
# Build shared/dynamic library
$(LIB_SO): $(LIB_LOBJS)
@echo "Building shared library $(LIB_SO)"
$(RM) -f $(LIB_SO) $(LIB_SO_MAJOR) $(LIB_SO_BASE)
$(CC) $(CFLAGS) $(LDFLAGS) $(LDLIBS) $(LIB_OPTS) -o $(LIB_SO) $(LIB_LOBJS)
ln -s $(LIB_SO) $(LIB_SO_BASE)
ln -s $(LIB_SO) $(LIB_SO_MAJOR)
test check: static FORCE
@$(MAKE) -C test test
example: static FORCE
@$(MAKE) -C example
clean:
@$(RM) $(LIB_OBJS) $(LIB_LOBJS) $(LIB_A) $(LIB_SO) $(LIB_SO_MAJOR) $(LIB_SO_BASE)
@$(MAKE) -C test clean
@$(MAKE) -C example clean
@echo "All clean."
install: shared
@echo "Installing into $(PREFIX)"
@mkdir -p $(DESTDIR)$(PREFIX)/include
@cp libmseed.h $(DESTDIR)$(PREFIX)/include
@mkdir -p $(DESTDIR)$(LIBDIR)/pkgconfig
@cp -a $(LIB_SO_BASE) $(LIB_SO_MAJOR) $(LIB_SO_NAME) $(LIB_SO) $(DESTDIR)$(LIBDIR)
@sed -e 's|@PREFIX@|$(PREFIX)|g' \
-e 's|@EXEC_PREFIX@|$(EXEC_PREFIX)|g' \
-e 's|@LIBDIR@|$(LIBDIR)|g' \
-e 's|@INCLUDEDIR@|$(PREFIX)/include|g' \
-e 's|@VERSION@|$(FULL_VER)|g' \
mseed.pc.in > $(DESTDIR)$(LIBDIR)/pkgconfig/mseed.pc
@mkdir -p $(DESTDIR)$(DOCDIR)/example
@cp -r example $(DESTDIR)$(DOCDIR)/
.SUFFIXES: .c .o .lo
# Standard object building
.c.o:
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@
# Standard object building for shared library using -fPIC
.c.lo:
$(CC) $(CPPFLAGS) $(CFLAGS) -fPIC -c $< -o $@
# Print Makefile expanded variables, e.g. % make print-LIB_SO
print-%:
@echo '$*=$($*)'
FORCE:

@ -0,0 +1,49 @@
#
# Nmake file for libmseed - MS Visual C/C++
# Use 'nmake -f Makefile.win'
NODEBUG=1
INCS = /I.
OPTS = /O2 /D_CRT_SECURE_NO_WARNINGS
LM_LIB = libmseed.lib
LM_DLL = libmseed.dll
LM_DEF = libmseed.def
OBJS = fileutils.obj \
genutils.obj \
msio.obj \
lookup.obj \
yyjson.obj \
msrutils.obj \
extraheaders.obj\
pack.obj \
packdata.obj \
tracelist.obj \
gmtime64.obj \
crc32c.obj \
parseutils.obj \
unpack.obj \
unpackdata.obj \
selection.obj \
logging.obj
all: lib
lib: $(OBJS)
link.exe /lib /nologo /OUT:$(LM_LIB) $(OBJS)
dll: $(OBJS)
link.exe /dll /nologo /OUT:$(LM_DLL) $(OBJS)
.c.obj:
$(CC) /nologo $(CFLAGS) $(INCS) $(OPTS) /c $<
# Run test suite
test: lib
pushd $@ && $(MAKE) /NOLOGO /f Makefile.win /$(MAKEFLAGS) & popd
# Clean-up directives
clean:
-del a.out core *.o *.obj *% *~ libmseed.exp $(LM_LIB) $(LM_DLL)
@pushd test && $(MAKE) /NOLOGO /f Makefile.win $@ /$(MAKEFLAGS) & popd

@ -0,0 +1,25 @@
-- Byte order handling in libmseed --
The miniSEED 3 format is defined as little-endian headers with the
endianess of the data payload explicitly defined by the encoding
value.
The SEED 2.4 standard allows data only SEED (miniSEED) to be either in
big (most significant byte first) or little (least significant byte
first) endian byte order. One exception is that Steim-1 and Steim-2
data compression are only defined as big-endian.
How libmseed determines the byte order of a 2.x record:
The byte order of a miniSEED 2.x record header including blockettes is
determined by checking if the record start year and day is a sane
value (e.g. year between 1900 and 2100 and day between 1 and 366).
The byte order of encoded data samples is determined by the byte order
flag in the Blockette 1000, if a Blockette 1000 is not present the
byte order is assumed to be the same as the header.
In what byte order libmseed creates 2.x records:
If the library ever creates miniSEED 2.x records, they will be in
big-endian byte order for maximum compatibility.

@ -0,0 +1,32 @@
# libmseed - The miniSEED library
The miniSEED library provides a framework for manipulation of SEED
data records, a format for commonly used for seismological time series
and related data. The library includes the functionality to read and
write data records, in addition to reconstructing time series from
multiple records.
The library should work in Unix-like, Windows and potentially other
environments.
## Documentation
The [Documentation](https://earthscope.github.io/libmseed) provides an
overview of using the library, a tutorial and function level details.
## License
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
[http://www.apache.org/licenses/LICENSE-2.0](http://www.apache.org/licenses/LICENSE-2.0)
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copyright (C) 2023 Chad Trabant, EarthScope Data Services

@ -0,0 +1,410 @@
/***************************************************************************
* CRC-32C calculation routines, clean and simple. Orignal file was named
* 'crc_sw.c' and found at: https://github.com/awslabs/aws-checksums
*
* All copyrights and license notifications have been retained.
* Unecessary routines have been removed for use in this code base.
***************************************************************************/
/*
* Copyright 2010-2017 Amazon.com, Inc. or its affiliates. All Rights Reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License").
* You may not use this file except in compliance with the License.
* A copy of the License is located at
*
* http://aws.amazon.com/apache2.0
*
* or in the "license" file accompanying this file. This file is distributed
* on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
* express or implied. See the License for the specific language governing
* permissions and limitations under the License.
*/
#include "libmseed.h"
/* The Castagnoli, iSCSI CRC32c polynomial (reverse of 0x1EDC6F41) */
#define CRC32C_POLYNOMIAL 0x82F63B78
/** Castagnoli CRC32c (iSCSI) lookup table for slice-by-4/8/16 */
/* Table truncated to 8 top-level tables from original, slice-by-16 is not supported in this code */
const uint32_t CRC32C_TABLE[8][256] = {
{
0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4, 0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB, // [0][0x08]
0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B, 0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24, // [0][0x10]
0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B, 0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384, // [0][0x18]
0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54, 0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B, // [0][0x20]
0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A, 0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35, // [0][0x28]
0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5, 0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA, // [0][0x30]
0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45, 0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A, // [0][0x38]
0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A, 0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595, // [0][0x40]
0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48, 0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957, // [0][0x48]
0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687, 0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198, // [0][0x50]
0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927, 0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38, // [0][0x58]
0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8, 0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7, // [0][0x60]
0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096, 0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789, // [0][0x68]
0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859, 0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46, // [0][0x70]
0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9, 0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6, // [0][0x78]
0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36, 0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829, // [0][0x80]
0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C, 0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93, // [0][0x88]
0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043, 0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C, // [0][0x90]
0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3, 0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC, // [0][0x98]
0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C, 0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033, // [0][0xa0]
0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652, 0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D, // [0][0xa8]
0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D, 0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982, // [0][0xb0]
0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D, 0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622, // [0][0xb8]
0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2, 0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED, // [0][0xc0]
0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530, 0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F, // [0][0xc8]
0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF, 0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0, // [0][0xd0]
0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F, 0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540, // [0][0xd8]
0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90, 0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F, // [0][0xe0]
0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE, 0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1, // [0][0xe8]
0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321, 0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E, // [0][0xf0]
0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81, 0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E, // [0][0xf8]
0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E, 0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 // [0][0x100]
},
{
0x00000000, 0x13A29877, 0x274530EE, 0x34E7A899, 0x4E8A61DC, 0x5D28F9AB, 0x69CF5132, 0x7A6DC945, // [1][0x08]
0x9D14C3B8, 0x8EB65BCF, 0xBA51F356, 0xA9F36B21, 0xD39EA264, 0xC03C3A13, 0xF4DB928A, 0xE7790AFD, // [1][0x10]
0x3FC5F181, 0x2C6769F6, 0x1880C16F, 0x0B225918, 0x714F905D, 0x62ED082A, 0x560AA0B3, 0x45A838C4, // [1][0x18]
0xA2D13239, 0xB173AA4E, 0x859402D7, 0x96369AA0, 0xEC5B53E5, 0xFFF9CB92, 0xCB1E630B, 0xD8BCFB7C, // [1][0x20]
0x7F8BE302, 0x6C297B75, 0x58CED3EC, 0x4B6C4B9B, 0x310182DE, 0x22A31AA9, 0x1644B230, 0x05E62A47, // [1][0x28]
0xE29F20BA, 0xF13DB8CD, 0xC5DA1054, 0xD6788823, 0xAC154166, 0xBFB7D911, 0x8B507188, 0x98F2E9FF, // [1][0x30]
0x404E1283, 0x53EC8AF4, 0x670B226D, 0x74A9BA1A, 0x0EC4735F, 0x1D66EB28, 0x298143B1, 0x3A23DBC6, // [1][0x38]
0xDD5AD13B, 0xCEF8494C, 0xFA1FE1D5, 0xE9BD79A2, 0x93D0B0E7, 0x80722890, 0xB4958009, 0xA737187E, // [1][0x40]
0xFF17C604, 0xECB55E73, 0xD852F6EA, 0xCBF06E9D, 0xB19DA7D8, 0xA23F3FAF, 0x96D89736, 0x857A0F41, // [1][0x48]
0x620305BC, 0x71A19DCB, 0x45463552, 0x56E4AD25, 0x2C896460, 0x3F2BFC17, 0x0BCC548E, 0x186ECCF9, // [1][0x50]
0xC0D23785, 0xD370AFF2, 0xE797076B, 0xF4359F1C, 0x8E585659, 0x9DFACE2E, 0xA91D66B7, 0xBABFFEC0, // [1][0x58]
0x5DC6F43D, 0x4E646C4A, 0x7A83C4D3, 0x69215CA4, 0x134C95E1, 0x00EE0D96, 0x3409A50F, 0x27AB3D78, // [1][0x60]
0x809C2506, 0x933EBD71, 0xA7D915E8, 0xB47B8D9F, 0xCE1644DA, 0xDDB4DCAD, 0xE9537434, 0xFAF1EC43, // [1][0x68]
0x1D88E6BE, 0x0E2A7EC9, 0x3ACDD650, 0x296F4E27, 0x53028762, 0x40A01F15, 0x7447B78C, 0x67E52FFB, // [1][0x70]
0xBF59D487, 0xACFB4CF0, 0x981CE469, 0x8BBE7C1E, 0xF1D3B55B, 0xE2712D2C, 0xD69685B5, 0xC5341DC2, // [1][0x78]
0x224D173F, 0x31EF8F48, 0x050827D1, 0x16AABFA6, 0x6CC776E3, 0x7F65EE94, 0x4B82460D, 0x5820DE7A, // [1][0x80]
0xFBC3FAF9, 0xE861628E, 0xDC86CA17, 0xCF245260, 0xB5499B25, 0xA6EB0352, 0x920CABCB, 0x81AE33BC, // [1][0x88]
0x66D73941, 0x7575A136, 0x419209AF, 0x523091D8, 0x285D589D, 0x3BFFC0EA, 0x0F186873, 0x1CBAF004, // [1][0x90]
0xC4060B78, 0xD7A4930F, 0xE3433B96, 0xF0E1A3E1, 0x8A8C6AA4, 0x992EF2D3, 0xADC95A4A, 0xBE6BC23D, // [1][0x98]
0x5912C8C0, 0x4AB050B7, 0x7E57F82E, 0x6DF56059, 0x1798A91C, 0x043A316B, 0x30DD99F2, 0x237F0185, // [1][0xa0]
0x844819FB, 0x97EA818C, 0xA30D2915, 0xB0AFB162, 0xCAC27827, 0xD960E050, 0xED8748C9, 0xFE25D0BE, // [1][0xa8]
0x195CDA43, 0x0AFE4234, 0x3E19EAAD, 0x2DBB72DA, 0x57D6BB9F, 0x447423E8, 0x70938B71, 0x63311306, // [1][0xb0]
0xBB8DE87A, 0xA82F700D, 0x9CC8D894, 0x8F6A40E3, 0xF50789A6, 0xE6A511D1, 0xD242B948, 0xC1E0213F, // [1][0xb8]
0x26992BC2, 0x353BB3B5, 0x01DC1B2C, 0x127E835B, 0x68134A1E, 0x7BB1D269, 0x4F567AF0, 0x5CF4E287, // [1][0xc0]
0x04D43CFD, 0x1776A48A, 0x23910C13, 0x30339464, 0x4A5E5D21, 0x59FCC556, 0x6D1B6DCF, 0x7EB9F5B8, // [1][0xc8]
0x99C0FF45, 0x8A626732, 0xBE85CFAB, 0xAD2757DC, 0xD74A9E99, 0xC4E806EE, 0xF00FAE77, 0xE3AD3600, // [1][0xd0]
0x3B11CD7C, 0x28B3550B, 0x1C54FD92, 0x0FF665E5, 0x759BACA0, 0x663934D7, 0x52DE9C4E, 0x417C0439, // [1][0xd8]
0xA6050EC4, 0xB5A796B3, 0x81403E2A, 0x92E2A65D, 0xE88F6F18, 0xFB2DF76F, 0xCFCA5FF6, 0xDC68C781, // [1][0xe0]
0x7B5FDFFF, 0x68FD4788, 0x5C1AEF11, 0x4FB87766, 0x35D5BE23, 0x26772654, 0x12908ECD, 0x013216BA, // [1][0xe8]
0xE64B1C47, 0xF5E98430, 0xC10E2CA9, 0xD2ACB4DE, 0xA8C17D9B, 0xBB63E5EC, 0x8F844D75, 0x9C26D502, // [1][0xf0]
0x449A2E7E, 0x5738B609, 0x63DF1E90, 0x707D86E7, 0x0A104FA2, 0x19B2D7D5, 0x2D557F4C, 0x3EF7E73B, // [1][0xf8]
0xD98EEDC6, 0xCA2C75B1, 0xFECBDD28, 0xED69455F, 0x97048C1A, 0x84A6146D, 0xB041BCF4, 0xA3E32483 // [1][0x100]
},
{
0x00000000, 0xA541927E, 0x4F6F520D, 0xEA2EC073, 0x9EDEA41A, 0x3B9F3664, 0xD1B1F617, 0x74F06469, // [2][0x08]
0x38513EC5, 0x9D10ACBB, 0x773E6CC8, 0xD27FFEB6, 0xA68F9ADF, 0x03CE08A1, 0xE9E0C8D2, 0x4CA15AAC, // [2][0x10]
0x70A27D8A, 0xD5E3EFF4, 0x3FCD2F87, 0x9A8CBDF9, 0xEE7CD990, 0x4B3D4BEE, 0xA1138B9D, 0x045219E3, // [2][0x18]
0x48F3434F, 0xEDB2D131, 0x079C1142, 0xA2DD833C, 0xD62DE755, 0x736C752B, 0x9942B558, 0x3C032726, // [2][0x20]
0xE144FB14, 0x4405696A, 0xAE2BA919, 0x0B6A3B67, 0x7F9A5F0E, 0xDADBCD70, 0x30F50D03, 0x95B49F7D, // [2][0x28]
0xD915C5D1, 0x7C5457AF, 0x967A97DC, 0x333B05A2, 0x47CB61CB, 0xE28AF3B5, 0x08A433C6, 0xADE5A1B8, // [2][0x30]
0x91E6869E, 0x34A714E0, 0xDE89D493, 0x7BC846ED, 0x0F382284, 0xAA79B0FA, 0x40577089, 0xE516E2F7, // [2][0x38]
0xA9B7B85B, 0x0CF62A25, 0xE6D8EA56, 0x43997828, 0x37691C41, 0x92288E3F, 0x78064E4C, 0xDD47DC32, // [2][0x40]
0xC76580D9, 0x622412A7, 0x880AD2D4, 0x2D4B40AA, 0x59BB24C3, 0xFCFAB6BD, 0x16D476CE, 0xB395E4B0, // [2][0x48]
0xFF34BE1C, 0x5A752C62, 0xB05BEC11, 0x151A7E6F, 0x61EA1A06, 0xC4AB8878, 0x2E85480B, 0x8BC4DA75, // [2][0x50]
0xB7C7FD53, 0x12866F2D, 0xF8A8AF5E, 0x5DE93D20, 0x29195949, 0x8C58CB37, 0x66760B44, 0xC337993A, // [2][0x58]
0x8F96C396, 0x2AD751E8, 0xC0F9919B, 0x65B803E5, 0x1148678C, 0xB409F5F2, 0x5E273581, 0xFB66A7FF, // [2][0x60]
0x26217BCD, 0x8360E9B3, 0x694E29C0, 0xCC0FBBBE, 0xB8FFDFD7, 0x1DBE4DA9, 0xF7908DDA, 0x52D11FA4, // [2][0x68]
0x1E704508, 0xBB31D776, 0x511F1705, 0xF45E857B, 0x80AEE112, 0x25EF736C, 0xCFC1B31F, 0x6A802161, // [2][0x70]
0x56830647, 0xF3C29439, 0x19EC544A, 0xBCADC634, 0xC85DA25D, 0x6D1C3023, 0x8732F050, 0x2273622E, // [2][0x78]
0x6ED23882, 0xCB93AAFC, 0x21BD6A8F, 0x84FCF8F1, 0xF00C9C98, 0x554D0EE6, 0xBF63CE95, 0x1A225CEB, // [2][0x80]
0x8B277743, 0x2E66E53D, 0xC448254E, 0x6109B730, 0x15F9D359, 0xB0B84127, 0x5A968154, 0xFFD7132A, // [2][0x88]
0xB3764986, 0x1637DBF8, 0xFC191B8B, 0x595889F5, 0x2DA8ED9C, 0x88E97FE2, 0x62C7BF91, 0xC7862DEF, // [2][0x90]
0xFB850AC9, 0x5EC498B7, 0xB4EA58C4, 0x11ABCABA, 0x655BAED3, 0xC01A3CAD, 0x2A34FCDE, 0x8F756EA0, // [2][0x98]
0xC3D4340C, 0x6695A672, 0x8CBB6601, 0x29FAF47F, 0x5D0A9016, 0xF84B0268, 0x1265C21B, 0xB7245065, // [2][0xa0]
0x6A638C57, 0xCF221E29, 0x250CDE5A, 0x804D4C24, 0xF4BD284D, 0x51FCBA33, 0xBBD27A40, 0x1E93E83E, // [2][0xa8]
0x5232B292, 0xF77320EC, 0x1D5DE09F, 0xB81C72E1, 0xCCEC1688, 0x69AD84F6, 0x83834485, 0x26C2D6FB, // [2][0xb0]
0x1AC1F1DD, 0xBF8063A3, 0x55AEA3D0, 0xF0EF31AE, 0x841F55C7, 0x215EC7B9, 0xCB7007CA, 0x6E3195B4, // [2][0xb8]
0x2290CF18, 0x87D15D66, 0x6DFF9D15, 0xC8BE0F6B, 0xBC4E6B02, 0x190FF97C, 0xF321390F, 0x5660AB71, // [2][0xc0]
0x4C42F79A, 0xE90365E4, 0x032DA597, 0xA66C37E9, 0xD29C5380, 0x77DDC1FE, 0x9DF3018D, 0x38B293F3, // [2][0xc8]
0x7413C95F, 0xD1525B21, 0x3B7C9B52, 0x9E3D092C, 0xEACD6D45, 0x4F8CFF3B, 0xA5A23F48, 0x00E3AD36, // [2][0xd0]
0x3CE08A10, 0x99A1186E, 0x738FD81D, 0xD6CE4A63, 0xA23E2E0A, 0x077FBC74, 0xED517C07, 0x4810EE79, // [2][0xd8]
0x04B1B4D5, 0xA1F026AB, 0x4BDEE6D8, 0xEE9F74A6, 0x9A6F10CF, 0x3F2E82B1, 0xD50042C2, 0x7041D0BC, // [2][0xe0]
0xAD060C8E, 0x08479EF0, 0xE2695E83, 0x4728CCFD, 0x33D8A894, 0x96993AEA, 0x7CB7FA99, 0xD9F668E7, // [2][0xe8]
0x9557324B, 0x3016A035, 0xDA386046, 0x7F79F238, 0x0B899651, 0xAEC8042F, 0x44E6C45C, 0xE1A75622, // [2][0xf0]
0xDDA47104, 0x78E5E37A, 0x92CB2309, 0x378AB177, 0x437AD51E, 0xE63B4760, 0x0C158713, 0xA954156D, // [2][0xf8]
0xE5F54FC1, 0x40B4DDBF, 0xAA9A1DCC, 0x0FDB8FB2, 0x7B2BEBDB, 0xDE6A79A5, 0x3444B9D6, 0x91052BA8 // [2][0x100]
},
{
0x00000000, 0xDD45AAB8, 0xBF672381, 0x62228939, 0x7B2231F3, 0xA6679B4B, 0xC4451272, 0x1900B8CA, // [3][0x08]
0xF64463E6, 0x2B01C95E, 0x49234067, 0x9466EADF, 0x8D665215, 0x5023F8AD, 0x32017194, 0xEF44DB2C, // [3][0x10]
0xE964B13D, 0x34211B85, 0x560392BC, 0x8B463804, 0x924680CE, 0x4F032A76, 0x2D21A34F, 0xF06409F7, // [3][0x18]
0x1F20D2DB, 0xC2657863, 0xA047F15A, 0x7D025BE2, 0x6402E328, 0xB9474990, 0xDB65C0A9, 0x06206A11, // [3][0x20]
0xD725148B, 0x0A60BE33, 0x6842370A, 0xB5079DB2, 0xAC072578, 0x71428FC0, 0x136006F9, 0xCE25AC41, // [3][0x28]
0x2161776D, 0xFC24DDD5, 0x9E0654EC, 0x4343FE54, 0x5A43469E, 0x8706EC26, 0xE524651F, 0x3861CFA7, // [3][0x30]
0x3E41A5B6, 0xE3040F0E, 0x81268637, 0x5C632C8F, 0x45639445, 0x98263EFD, 0xFA04B7C4, 0x27411D7C, // [3][0x38]
0xC805C650, 0x15406CE8, 0x7762E5D1, 0xAA274F69, 0xB327F7A3, 0x6E625D1B, 0x0C40D422, 0xD1057E9A, // [3][0x40]
0xABA65FE7, 0x76E3F55F, 0x14C17C66, 0xC984D6DE, 0xD0846E14, 0x0DC1C4AC, 0x6FE34D95, 0xB2A6E72D, // [3][0x48]
0x5DE23C01, 0x80A796B9, 0xE2851F80, 0x3FC0B538, 0x26C00DF2, 0xFB85A74A, 0x99A72E73, 0x44E284CB, // [3][0x50]
0x42C2EEDA, 0x9F874462, 0xFDA5CD5B, 0x20E067E3, 0x39E0DF29, 0xE4A57591, 0x8687FCA8, 0x5BC25610, // [3][0x58]
0xB4868D3C, 0x69C32784, 0x0BE1AEBD, 0xD6A40405, 0xCFA4BCCF, 0x12E11677, 0x70C39F4E, 0xAD8635F6, // [3][0x60]
0x7C834B6C, 0xA1C6E1D4, 0xC3E468ED, 0x1EA1C255, 0x07A17A9F, 0xDAE4D027, 0xB8C6591E, 0x6583F3A6, // [3][0x68]
0x8AC7288A, 0x57828232, 0x35A00B0B, 0xE8E5A1B3, 0xF1E51979, 0x2CA0B3C1, 0x4E823AF8, 0x93C79040, // [3][0x70]
0x95E7FA51, 0x48A250E9, 0x2A80D9D0, 0xF7C57368, 0xEEC5CBA2, 0x3380611A, 0x51A2E823, 0x8CE7429B, // [3][0x78]
0x63A399B7, 0xBEE6330F, 0xDCC4BA36, 0x0181108E, 0x1881A844, 0xC5C402FC, 0xA7E68BC5, 0x7AA3217D, // [3][0x80]
0x52A0C93F, 0x8FE56387, 0xEDC7EABE, 0x30824006, 0x2982F8CC, 0xF4C75274, 0x96E5DB4D, 0x4BA071F5, // [3][0x88]
0xA4E4AAD9, 0x79A10061, 0x1B838958, 0xC6C623E0, 0xDFC69B2A, 0x02833192, 0x60A1B8AB, 0xBDE41213, // [3][0x90]
0xBBC47802, 0x6681D2BA, 0x04A35B83, 0xD9E6F13B, 0xC0E649F1, 0x1DA3E349, 0x7F816A70, 0xA2C4C0C8, // [3][0x98]
0x4D801BE4, 0x90C5B15C, 0xF2E73865, 0x2FA292DD, 0x36A22A17, 0xEBE780AF, 0x89C50996, 0x5480A32E, // [3][0xa0]
0x8585DDB4, 0x58C0770C, 0x3AE2FE35, 0xE7A7548D, 0xFEA7EC47, 0x23E246FF, 0x41C0CFC6, 0x9C85657E, // [3][0xa8]
0x73C1BE52, 0xAE8414EA, 0xCCA69DD3, 0x11E3376B, 0x08E38FA1, 0xD5A62519, 0xB784AC20, 0x6AC10698, // [3][0xb0]
0x6CE16C89, 0xB1A4C631, 0xD3864F08, 0x0EC3E5B0, 0x17C35D7A, 0xCA86F7C2, 0xA8A47EFB, 0x75E1D443, // [3][0xb8]
0x9AA50F6F, 0x47E0A5D7, 0x25C22CEE, 0xF8878656, 0xE1873E9C, 0x3CC29424, 0x5EE01D1D, 0x83A5B7A5, // [3][0xc0]
0xF90696D8, 0x24433C60, 0x4661B559, 0x9B241FE1, 0x8224A72B, 0x5F610D93, 0x3D4384AA, 0xE0062E12, // [3][0xc8]
0x0F42F53E, 0xD2075F86, 0xB025D6BF, 0x6D607C07, 0x7460C4CD, 0xA9256E75, 0xCB07E74C, 0x16424DF4, // [3][0xd0]
0x106227E5, 0xCD278D5D, 0xAF050464, 0x7240AEDC, 0x6B401616, 0xB605BCAE, 0xD4273597, 0x09629F2F, // [3][0xd8]
0xE6264403, 0x3B63EEBB, 0x59416782, 0x8404CD3A, 0x9D0475F0, 0x4041DF48, 0x22635671, 0xFF26FCC9, // [3][0xe0]
0x2E238253, 0xF36628EB, 0x9144A1D2, 0x4C010B6A, 0x5501B3A0, 0x88441918, 0xEA669021, 0x37233A99, // [3][0xe8]
0xD867E1B5, 0x05224B0D, 0x6700C234, 0xBA45688C, 0xA345D046, 0x7E007AFE, 0x1C22F3C7, 0xC167597F, // [3][0xf0]
0xC747336E, 0x1A0299D6, 0x782010EF, 0xA565BA57, 0xBC65029D, 0x6120A825, 0x0302211C, 0xDE478BA4, // [3][0xf8]
0x31035088, 0xEC46FA30, 0x8E647309, 0x5321D9B1, 0x4A21617B, 0x9764CBC3, 0xF54642FA, 0x2803E842 // [3][0x100]
},
{
0x00000000, 0x38116FAC, 0x7022DF58, 0x4833B0F4, 0xE045BEB0, 0xD854D11C, 0x906761E8, 0xA8760E44, // [4][0x08]
0xC5670B91, 0xFD76643D, 0xB545D4C9, 0x8D54BB65, 0x2522B521, 0x1D33DA8D, 0x55006A79, 0x6D1105D5, // [4][0x10]
0x8F2261D3, 0xB7330E7F, 0xFF00BE8B, 0xC711D127, 0x6F67DF63, 0x5776B0CF, 0x1F45003B, 0x27546F97, // [4][0x18]
0x4A456A42, 0x725405EE, 0x3A67B51A, 0x0276DAB6, 0xAA00D4F2, 0x9211BB5E, 0xDA220BAA, 0xE2336406, // [4][0x20]
0x1BA8B557, 0x23B9DAFB, 0x6B8A6A0F, 0x539B05A3, 0xFBED0BE7, 0xC3FC644B, 0x8BCFD4BF, 0xB3DEBB13, // [4][0x28]
0xDECFBEC6, 0xE6DED16A, 0xAEED619E, 0x96FC0E32, 0x3E8A0076, 0x069B6FDA, 0x4EA8DF2E, 0x76B9B082, // [4][0x30]
0x948AD484, 0xAC9BBB28, 0xE4A80BDC, 0xDCB96470, 0x74CF6A34, 0x4CDE0598, 0x04EDB56C, 0x3CFCDAC0, // [4][0x38]
0x51EDDF15, 0x69FCB0B9, 0x21CF004D, 0x19DE6FE1, 0xB1A861A5, 0x89B90E09, 0xC18ABEFD, 0xF99BD151, // [4][0x40]
0x37516AAE, 0x0F400502, 0x4773B5F6, 0x7F62DA5A, 0xD714D41E, 0xEF05BBB2, 0xA7360B46, 0x9F2764EA, // [4][0x48]
0xF236613F, 0xCA270E93, 0x8214BE67, 0xBA05D1CB, 0x1273DF8F, 0x2A62B023, 0x625100D7, 0x5A406F7B, // [4][0x50]
0xB8730B7D, 0x806264D1, 0xC851D425, 0xF040BB89, 0x5836B5CD, 0x6027DA61, 0x28146A95, 0x10050539, // [4][0x58]
0x7D1400EC, 0x45056F40, 0x0D36DFB4, 0x3527B018, 0x9D51BE5C, 0xA540D1F0, 0xED736104, 0xD5620EA8, // [4][0x60]
0x2CF9DFF9, 0x14E8B055, 0x5CDB00A1, 0x64CA6F0D, 0xCCBC6149, 0xF4AD0EE5, 0xBC9EBE11, 0x848FD1BD, // [4][0x68]
0xE99ED468, 0xD18FBBC4, 0x99BC0B30, 0xA1AD649C, 0x09DB6AD8, 0x31CA0574, 0x79F9B580, 0x41E8DA2C, // [4][0x70]
0xA3DBBE2A, 0x9BCAD186, 0xD3F96172, 0xEBE80EDE, 0x439E009A, 0x7B8F6F36, 0x33BCDFC2, 0x0BADB06E, // [4][0x78]
0x66BCB5BB, 0x5EADDA17, 0x169E6AE3, 0x2E8F054F, 0x86F90B0B, 0xBEE864A7, 0xF6DBD453, 0xCECABBFF, // [4][0x80]
0x6EA2D55C, 0x56B3BAF0, 0x1E800A04, 0x269165A8, 0x8EE76BEC, 0xB6F60440, 0xFEC5B4B4, 0xC6D4DB18, // [4][0x88]
0xABC5DECD, 0x93D4B161, 0xDBE70195, 0xE3F66E39, 0x4B80607D, 0x73910FD1, 0x3BA2BF25, 0x03B3D089, // [4][0x90]
0xE180B48F, 0xD991DB23, 0x91A26BD7, 0xA9B3047B, 0x01C50A3F, 0x39D46593, 0x71E7D567, 0x49F6BACB, // [4][0x98]
0x24E7BF1E, 0x1CF6D0B2, 0x54C56046, 0x6CD40FEA, 0xC4A201AE, 0xFCB36E02, 0xB480DEF6, 0x8C91B15A, // [4][0xa0]
0x750A600B, 0x4D1B0FA7, 0x0528BF53, 0x3D39D0FF, 0x954FDEBB, 0xAD5EB117, 0xE56D01E3, 0xDD7C6E4F, // [4][0xa8]
0xB06D6B9A, 0x887C0436, 0xC04FB4C2, 0xF85EDB6E, 0x5028D52A, 0x6839BA86, 0x200A0A72, 0x181B65DE, // [4][0xb0]
0xFA2801D8, 0xC2396E74, 0x8A0ADE80, 0xB21BB12C, 0x1A6DBF68, 0x227CD0C4, 0x6A4F6030, 0x525E0F9C, // [4][0xb8]
0x3F4F0A49, 0x075E65E5, 0x4F6DD511, 0x777CBABD, 0xDF0AB4F9, 0xE71BDB55, 0xAF286BA1, 0x9739040D, // [4][0xc0]
0x59F3BFF2, 0x61E2D05E, 0x29D160AA, 0x11C00F06, 0xB9B60142, 0x81A76EEE, 0xC994DE1A, 0xF185B1B6, // [4][0xc8]
0x9C94B463, 0xA485DBCF, 0xECB66B3B, 0xD4A70497, 0x7CD10AD3, 0x44C0657F, 0x0CF3D58B, 0x34E2BA27, // [4][0xd0]
0xD6D1DE21, 0xEEC0B18D, 0xA6F30179, 0x9EE26ED5, 0x36946091, 0x0E850F3D, 0x46B6BFC9, 0x7EA7D065, // [4][0xd8]
0x13B6D5B0, 0x2BA7BA1C, 0x63940AE8, 0x5B856544, 0xF3F36B00, 0xCBE204AC, 0x83D1B458, 0xBBC0DBF4, // [4][0xe0]
0x425B0AA5, 0x7A4A6509, 0x3279D5FD, 0x0A68BA51, 0xA21EB415, 0x9A0FDBB9, 0xD23C6B4D, 0xEA2D04E1, // [4][0xe8]
0x873C0134, 0xBF2D6E98, 0xF71EDE6C, 0xCF0FB1C0, 0x6779BF84, 0x5F68D028, 0x175B60DC, 0x2F4A0F70, // [4][0xf0]
0xCD796B76, 0xF56804DA, 0xBD5BB42E, 0x854ADB82, 0x2D3CD5C6, 0x152DBA6A, 0x5D1E0A9E, 0x650F6532, // [4][0xf8]
0x081E60E7, 0x300F0F4B, 0x783CBFBF, 0x402DD013, 0xE85BDE57, 0xD04AB1FB, 0x9879010F, 0xA0686EA3 // [4][0x100]
},
{
0x00000000, 0xEF306B19, 0xDB8CA0C3, 0x34BCCBDA, 0xB2F53777, 0x5DC55C6E, 0x697997B4, 0x8649FCAD, // [5][0x08]
0x6006181F, 0x8F367306, 0xBB8AB8DC, 0x54BAD3C5, 0xD2F32F68, 0x3DC34471, 0x097F8FAB, 0xE64FE4B2, // [5][0x10]
0xC00C303E, 0x2F3C5B27, 0x1B8090FD, 0xF4B0FBE4, 0x72F90749, 0x9DC96C50, 0xA975A78A, 0x4645CC93, // [5][0x18]
0xA00A2821, 0x4F3A4338, 0x7B8688E2, 0x94B6E3FB, 0x12FF1F56, 0xFDCF744F, 0xC973BF95, 0x2643D48C, // [5][0x20]
0x85F4168D, 0x6AC47D94, 0x5E78B64E, 0xB148DD57, 0x370121FA, 0xD8314AE3, 0xEC8D8139, 0x03BDEA20, // [5][0x28]
0xE5F20E92, 0x0AC2658B, 0x3E7EAE51, 0xD14EC548, 0x570739E5, 0xB83752FC, 0x8C8B9926, 0x63BBF23F, // [5][0x30]
0x45F826B3, 0xAAC84DAA, 0x9E748670, 0x7144ED69, 0xF70D11C4, 0x183D7ADD, 0x2C81B107, 0xC3B1DA1E, // [5][0x38]
0x25FE3EAC, 0xCACE55B5, 0xFE729E6F, 0x1142F576, 0x970B09DB, 0x783B62C2, 0x4C87A918, 0xA3B7C201, // [5][0x40]
0x0E045BEB, 0xE13430F2, 0xD588FB28, 0x3AB89031, 0xBCF16C9C, 0x53C10785, 0x677DCC5F, 0x884DA746, // [5][0x48]
0x6E0243F4, 0x813228ED, 0xB58EE337, 0x5ABE882E, 0xDCF77483, 0x33C71F9A, 0x077BD440, 0xE84BBF59, // [5][0x50]
0xCE086BD5, 0x213800CC, 0x1584CB16, 0xFAB4A00F, 0x7CFD5CA2, 0x93CD37BB, 0xA771FC61, 0x48419778, // [5][0x58]
0xAE0E73CA, 0x413E18D3, 0x7582D309, 0x9AB2B810, 0x1CFB44BD, 0xF3CB2FA4, 0xC777E47E, 0x28478F67, // [5][0x60]
0x8BF04D66, 0x64C0267F, 0x507CEDA5, 0xBF4C86BC, 0x39057A11, 0xD6351108, 0xE289DAD2, 0x0DB9B1CB, // [5][0x68]
0xEBF65579, 0x04C63E60, 0x307AF5BA, 0xDF4A9EA3, 0x5903620E, 0xB6330917, 0x828FC2CD, 0x6DBFA9D4, // [5][0x70]
0x4BFC7D58, 0xA4CC1641, 0x9070DD9B, 0x7F40B682, 0xF9094A2F, 0x16392136, 0x2285EAEC, 0xCDB581F5, // [5][0x78]
0x2BFA6547, 0xC4CA0E5E, 0xF076C584, 0x1F46AE9D, 0x990F5230, 0x763F3929, 0x4283F2F3, 0xADB399EA, // [5][0x80]
0x1C08B7D6, 0xF338DCCF, 0xC7841715, 0x28B47C0C, 0xAEFD80A1, 0x41CDEBB8, 0x75712062, 0x9A414B7B, // [5][0x88]
0x7C0EAFC9, 0x933EC4D0, 0xA7820F0A, 0x48B26413, 0xCEFB98BE, 0x21CBF3A7, 0x1577387D, 0xFA475364, // [5][0x90]
0xDC0487E8, 0x3334ECF1, 0x0788272B, 0xE8B84C32, 0x6EF1B09F, 0x81C1DB86, 0xB57D105C, 0x5A4D7B45, // [5][0x98]
0xBC029FF7, 0x5332F4EE, 0x678E3F34, 0x88BE542D, 0x0EF7A880, 0xE1C7C399, 0xD57B0843, 0x3A4B635A, // [5][0xa0]
0x99FCA15B, 0x76CCCA42, 0x42700198, 0xAD406A81, 0x2B09962C, 0xC439FD35, 0xF08536EF, 0x1FB55DF6, // [5][0xa8]
0xF9FAB944, 0x16CAD25D, 0x22761987, 0xCD46729E, 0x4B0F8E33, 0xA43FE52A, 0x90832EF0, 0x7FB345E9, // [5][0xb0]
0x59F09165, 0xB6C0FA7C, 0x827C31A6, 0x6D4C5ABF, 0xEB05A612, 0x0435CD0B, 0x308906D1, 0xDFB96DC8, // [5][0xb8]
0x39F6897A, 0xD6C6E263, 0xE27A29B9, 0x0D4A42A0, 0x8B03BE0D, 0x6433D514, 0x508F1ECE, 0xBFBF75D7, // [5][0xc0]
0x120CEC3D, 0xFD3C8724, 0xC9804CFE, 0x26B027E7, 0xA0F9DB4A, 0x4FC9B053, 0x7B757B89, 0x94451090, // [5][0xc8]
0x720AF422, 0x9D3A9F3B, 0xA98654E1, 0x46B63FF8, 0xC0FFC355, 0x2FCFA84C, 0x1B736396, 0xF443088F, // [5][0xd0]
0xD200DC03, 0x3D30B71A, 0x098C7CC0, 0xE6BC17D9, 0x60F5EB74, 0x8FC5806D, 0xBB794BB7, 0x544920AE, // [5][0xd8]
0xB206C41C, 0x5D36AF05, 0x698A64DF, 0x86BA0FC6, 0x00F3F36B, 0xEFC39872, 0xDB7F53A8, 0x344F38B1, // [5][0xe0]
0x97F8FAB0, 0x78C891A9, 0x4C745A73, 0xA344316A, 0x250DCDC7, 0xCA3DA6DE, 0xFE816D04, 0x11B1061D, // [5][0xe8]
0xF7FEE2AF, 0x18CE89B6, 0x2C72426C, 0xC3422975, 0x450BD5D8, 0xAA3BBEC1, 0x9E87751B, 0x71B71E02, // [5][0xf0]
0x57F4CA8E, 0xB8C4A197, 0x8C786A4D, 0x63480154, 0xE501FDF9, 0x0A3196E0, 0x3E8D5D3A, 0xD1BD3623, // [5][0xf8]
0x37F2D291, 0xD8C2B988, 0xEC7E7252, 0x034E194B, 0x8507E5E6, 0x6A378EFF, 0x5E8B4525, 0xB1BB2E3C // [5][0x100]
},
{
0x00000000, 0x68032CC8, 0xD0065990, 0xB8057558, 0xA5E0C5D1, 0xCDE3E919, 0x75E69C41, 0x1DE5B089, // [6][0x08]
0x4E2DFD53, 0x262ED19B, 0x9E2BA4C3, 0xF628880B, 0xEBCD3882, 0x83CE144A, 0x3BCB6112, 0x53C84DDA, // [6][0x10]
0x9C5BFAA6, 0xF458D66E, 0x4C5DA336, 0x245E8FFE, 0x39BB3F77, 0x51B813BF, 0xE9BD66E7, 0x81BE4A2F, // [6][0x18]
0xD27607F5, 0xBA752B3D, 0x02705E65, 0x6A7372AD, 0x7796C224, 0x1F95EEEC, 0xA7909BB4, 0xCF93B77C, // [6][0x20]
0x3D5B83BD, 0x5558AF75, 0xED5DDA2D, 0x855EF6E5, 0x98BB466C, 0xF0B86AA4, 0x48BD1FFC, 0x20BE3334, // [6][0x28]
0x73767EEE, 0x1B755226, 0xA370277E, 0xCB730BB6, 0xD696BB3F, 0xBE9597F7, 0x0690E2AF, 0x6E93CE67, // [6][0x30]
0xA100791B, 0xC90355D3, 0x7106208B, 0x19050C43, 0x04E0BCCA, 0x6CE39002, 0xD4E6E55A, 0xBCE5C992, // [6][0x38]
0xEF2D8448, 0x872EA880, 0x3F2BDDD8, 0x5728F110, 0x4ACD4199, 0x22CE6D51, 0x9ACB1809, 0xF2C834C1, // [6][0x40]
0x7AB7077A, 0x12B42BB2, 0xAAB15EEA, 0xC2B27222, 0xDF57C2AB, 0xB754EE63, 0x0F519B3B, 0x6752B7F3, // [6][0x48]
0x349AFA29, 0x5C99D6E1, 0xE49CA3B9, 0x8C9F8F71, 0x917A3FF8, 0xF9791330, 0x417C6668, 0x297F4AA0, // [6][0x50]
0xE6ECFDDC, 0x8EEFD114, 0x36EAA44C, 0x5EE98884, 0x430C380D, 0x2B0F14C5, 0x930A619D, 0xFB094D55, // [6][0x58]
0xA8C1008F, 0xC0C22C47, 0x78C7591F, 0x10C475D7, 0x0D21C55E, 0x6522E996, 0xDD279CCE, 0xB524B006, // [6][0x60]
0x47EC84C7, 0x2FEFA80F, 0x97EADD57, 0xFFE9F19F, 0xE20C4116, 0x8A0F6DDE, 0x320A1886, 0x5A09344E, // [6][0x68]
0x09C17994, 0x61C2555C, 0xD9C72004, 0xB1C40CCC, 0xAC21BC45, 0xC422908D, 0x7C27E5D5, 0x1424C91D, // [6][0x70]
0xDBB77E61, 0xB3B452A9, 0x0BB127F1, 0x63B20B39, 0x7E57BBB0, 0x16549778, 0xAE51E220, 0xC652CEE8, // [6][0x78]
0x959A8332, 0xFD99AFFA, 0x459CDAA2, 0x2D9FF66A, 0x307A46E3, 0x58796A2B, 0xE07C1F73, 0x887F33BB, // [6][0x80]
0xF56E0EF4, 0x9D6D223C, 0x25685764, 0x4D6B7BAC, 0x508ECB25, 0x388DE7ED, 0x808892B5, 0xE88BBE7D, // [6][0x88]
0xBB43F3A7, 0xD340DF6F, 0x6B45AA37, 0x034686FF, 0x1EA33676, 0x76A01ABE, 0xCEA56FE6, 0xA6A6432E, // [6][0x90]
0x6935F452, 0x0136D89A, 0xB933ADC2, 0xD130810A, 0xCCD53183, 0xA4D61D4B, 0x1CD36813, 0x74D044DB, // [6][0x98]
0x27180901, 0x4F1B25C9, 0xF71E5091, 0x9F1D7C59, 0x82F8CCD0, 0xEAFBE018, 0x52FE9540, 0x3AFDB988, // [6][0xa0]
0xC8358D49, 0xA036A181, 0x1833D4D9, 0x7030F811, 0x6DD54898, 0x05D66450, 0xBDD31108, 0xD5D03DC0, // [6][0xa8]
0x8618701A, 0xEE1B5CD2, 0x561E298A, 0x3E1D0542, 0x23F8B5CB, 0x4BFB9903, 0xF3FEEC5B, 0x9BFDC093, // [6][0xb0]
0x546E77EF, 0x3C6D5B27, 0x84682E7F, 0xEC6B02B7, 0xF18EB23E, 0x998D9EF6, 0x2188EBAE, 0x498BC766, // [6][0xb8]
0x1A438ABC, 0x7240A674, 0xCA45D32C, 0xA246FFE4, 0xBFA34F6D, 0xD7A063A5, 0x6FA516FD, 0x07A63A35, // [6][0xc0]
0x8FD9098E, 0xE7DA2546, 0x5FDF501E, 0x37DC7CD6, 0x2A39CC5F, 0x423AE097, 0xFA3F95CF, 0x923CB907, // [6][0xc8]
0xC1F4F4DD, 0xA9F7D815, 0x11F2AD4D, 0x79F18185, 0x6414310C, 0x0C171DC4, 0xB412689C, 0xDC114454, // [6][0xd0]
0x1382F328, 0x7B81DFE0, 0xC384AAB8, 0xAB878670, 0xB66236F9, 0xDE611A31, 0x66646F69, 0x0E6743A1, // [6][0xd8]
0x5DAF0E7B, 0x35AC22B3, 0x8DA957EB, 0xE5AA7B23, 0xF84FCBAA, 0x904CE762, 0x2849923A, 0x404ABEF2, // [6][0xe0]
0xB2828A33, 0xDA81A6FB, 0x6284D3A3, 0x0A87FF6B, 0x17624FE2, 0x7F61632A, 0xC7641672, 0xAF673ABA, // [6][0xe8]
0xFCAF7760, 0x94AC5BA8, 0x2CA92EF0, 0x44AA0238, 0x594FB2B1, 0x314C9E79, 0x8949EB21, 0xE14AC7E9, // [6][0xf0]
0x2ED97095, 0x46DA5C5D, 0xFEDF2905, 0x96DC05CD, 0x8B39B544, 0xE33A998C, 0x5B3FECD4, 0x333CC01C, // [6][0xf8]
0x60F48DC6, 0x08F7A10E, 0xB0F2D456, 0xD8F1F89E, 0xC5144817, 0xAD1764DF, 0x15121187, 0x7D113D4F // [6][0x100]
},
{
0x00000000, 0x493C7D27, 0x9278FA4E, 0xDB448769, 0x211D826D, 0x6821FF4A, 0xB3657823, 0xFA590504, // [7][0x08]
0x423B04DA, 0x0B0779FD, 0xD043FE94, 0x997F83B3, 0x632686B7, 0x2A1AFB90, 0xF15E7CF9, 0xB86201DE, // [7][0x10]
0x847609B4, 0xCD4A7493, 0x160EF3FA, 0x5F328EDD, 0xA56B8BD9, 0xEC57F6FE, 0x37137197, 0x7E2F0CB0, // [7][0x18]
0xC64D0D6E, 0x8F717049, 0x5435F720, 0x1D098A07, 0xE7508F03, 0xAE6CF224, 0x7528754D, 0x3C14086A, // [7][0x20]
0x0D006599, 0x443C18BE, 0x9F789FD7, 0xD644E2F0, 0x2C1DE7F4, 0x65219AD3, 0xBE651DBA, 0xF759609D, // [7][0x28]
0x4F3B6143, 0x06071C64, 0xDD439B0D, 0x947FE62A, 0x6E26E32E, 0x271A9E09, 0xFC5E1960, 0xB5626447, // [7][0x30]
0x89766C2D, 0xC04A110A, 0x1B0E9663, 0x5232EB44, 0xA86BEE40, 0xE1579367, 0x3A13140E, 0x732F6929, // [7][0x38]
0xCB4D68F7, 0x827115D0, 0x593592B9, 0x1009EF9E, 0xEA50EA9A, 0xA36C97BD, 0x782810D4, 0x31146DF3, // [7][0x40]
0x1A00CB32, 0x533CB615, 0x8878317C, 0xC1444C5B, 0x3B1D495F, 0x72213478, 0xA965B311, 0xE059CE36, // [7][0x48]
0x583BCFE8, 0x1107B2CF, 0xCA4335A6, 0x837F4881, 0x79264D85, 0x301A30A2, 0xEB5EB7CB, 0xA262CAEC, // [7][0x50]
0x9E76C286, 0xD74ABFA1, 0x0C0E38C8, 0x453245EF, 0xBF6B40EB, 0xF6573DCC, 0x2D13BAA5, 0x642FC782, // [7][0x58]
0xDC4DC65C, 0x9571BB7B, 0x4E353C12, 0x07094135, 0xFD504431, 0xB46C3916, 0x6F28BE7F, 0x2614C358, // [7][0x60]
0x1700AEAB, 0x5E3CD38C, 0x857854E5, 0xCC4429C2, 0x361D2CC6, 0x7F2151E1, 0xA465D688, 0xED59ABAF, // [7][0x68]
0x553BAA71, 0x1C07D756, 0xC743503F, 0x8E7F2D18, 0x7426281C, 0x3D1A553B, 0xE65ED252, 0xAF62AF75, // [7][0x70]
0x9376A71F, 0xDA4ADA38, 0x010E5D51, 0x48322076, 0xB26B2572, 0xFB575855, 0x2013DF3C, 0x692FA21B, // [7][0x78]
0xD14DA3C5, 0x9871DEE2, 0x4335598B, 0x0A0924AC, 0xF05021A8, 0xB96C5C8F, 0x6228DBE6, 0x2B14A6C1, // [7][0x80]
0x34019664, 0x7D3DEB43, 0xA6796C2A, 0xEF45110D, 0x151C1409, 0x5C20692E, 0x8764EE47, 0xCE589360, // [7][0x88]
0x763A92BE, 0x3F06EF99, 0xE44268F0, 0xAD7E15D7, 0x572710D3, 0x1E1B6DF4, 0xC55FEA9D, 0x8C6397BA, // [7][0x90]
0xB0779FD0, 0xF94BE2F7, 0x220F659E, 0x6B3318B9, 0x916A1DBD, 0xD856609A, 0x0312E7F3, 0x4A2E9AD4, // [7][0x98]
0xF24C9B0A, 0xBB70E62D, 0x60346144, 0x29081C63, 0xD3511967, 0x9A6D6440, 0x4129E329, 0x08159E0E, // [7][0xa0]
0x3901F3FD, 0x703D8EDA, 0xAB7909B3, 0xE2457494, 0x181C7190, 0x51200CB7, 0x8A648BDE, 0xC358F6F9, // [7][0xa8]
0x7B3AF727, 0x32068A00, 0xE9420D69, 0xA07E704E, 0x5A27754A, 0x131B086D, 0xC85F8F04, 0x8163F223, // [7][0xb0]
0xBD77FA49, 0xF44B876E, 0x2F0F0007, 0x66337D20, 0x9C6A7824, 0xD5560503, 0x0E12826A, 0x472EFF4D, // [7][0xb8]
0xFF4CFE93, 0xB67083B4, 0x6D3404DD, 0x240879FA, 0xDE517CFE, 0x976D01D9, 0x4C2986B0, 0x0515FB97, // [7][0xc0]
0x2E015D56, 0x673D2071, 0xBC79A718, 0xF545DA3F, 0x0F1CDF3B, 0x4620A21C, 0x9D642575, 0xD4585852, // [7][0xc8]
0x6C3A598C, 0x250624AB, 0xFE42A3C2, 0xB77EDEE5, 0x4D27DBE1, 0x041BA6C6, 0xDF5F21AF, 0x96635C88, // [7][0xd0]
0xAA7754E2, 0xE34B29C5, 0x380FAEAC, 0x7133D38B, 0x8B6AD68F, 0xC256ABA8, 0x19122CC1, 0x502E51E6, // [7][0xd8]
0xE84C5038, 0xA1702D1F, 0x7A34AA76, 0x3308D751, 0xC951D255, 0x806DAF72, 0x5B29281B, 0x1215553C, // [7][0xe0]
0x230138CF, 0x6A3D45E8, 0xB179C281, 0xF845BFA6, 0x021CBAA2, 0x4B20C785, 0x906440EC, 0xD9583DCB, // [7][0xe8]
0x613A3C15, 0x28064132, 0xF342C65B, 0xBA7EBB7C, 0x4027BE78, 0x091BC35F, 0xD25F4436, 0x9B633911, // [7][0xf0]
0xA777317B, 0xEE4B4C5C, 0x350FCB35, 0x7C33B612, 0x866AB316, 0xCF56CE31, 0x14124958, 0x5D2E347F, // [7][0xf8]
0xE54C35A1, 0xAC704886, 0x7734CFEF, 0x3E08B2C8, 0xC451B7CC, 0x8D6DCAEB, 0x56294D82, 0x1F1530A5 // [7][0x100]
}
};
/* private (static) function factoring out byte-by-byte CRC computation using just one slice of the lookup table*/
static uint32_t s_crc_generic_sb1(const uint8_t *input, int length, uint32_t crc, const uint32_t *table_ptr) {
uint32_t(*table)[8][256] = (uint32_t(*)[8][256])table_ptr;
while (length-- > 0) {
crc = (crc >> 8) ^ (*table)[0][(crc & 0xff) ^ *input++];
}
return crc;
}
/* The inner loops of the CRC functions that process large blocks of data work best when input is aligned*/
/* This function begins processing input data one byte at a time until the input pointer is 4-byte aligned*/
/* Advances the input pointer and reduces the length (both passed by reference)*/
static inline uint32_t s_crc_generic_align(
const uint8_t **input,
int *length,
uint32_t crc,
const uint32_t *table_ptr) {
/* Get the 4-byte memory alignment of our input buffer by looking at the least significant 2 bits*/
size_t input_alignment = ((size_t)*input) & 0x3;
/* Compute the number of input bytes that precede the first 4-byte aligned block (will be in range 0-3)*/
size_t leading = (4 - input_alignment) & 0x3;
/* Determine what's left without the leading input bytes (might be negative)*/
size_t remaining = *length - leading;
/* Process unaligned leading input bytes one at a time*/
if (leading && remaining > 0) {
crc = s_crc_generic_sb1(*input, (uint32_t)leading, crc, table_ptr);
*input += leading;
*length -= (int)leading;
}
return crc;
}
/* private (static) function to compute a generic slice-by-4 CRC using the specified lookup table (4 table slices)*/
static uint32_t s_crc_generic_sb4(const uint8_t *input, int length, uint32_t crc, const uint32_t *table_ptr) {
const uint32_t *current = (const uint32_t *)input;
int remaining = length;
uint32_t(*table)[8][256] = (uint32_t(*)[8][256])table_ptr;
while (remaining >= 4) {
crc ^= *current++;
crc = (*table)[3][crc & 0xff] ^ (*table)[2][(crc >> 8) & 0xff] ^ (*table)[1][(crc >> 16) & 0xff] ^
(*table)[0][crc >> 24];
remaining -= 4;
}
return s_crc_generic_sb1(&input[length - remaining], remaining, crc, table_ptr);
}
/* private (static) function to compute a generic slice-by-8 CRC using the specified lookup table (8 table slices)*/
static uint32_t s_crc_generic_sb8(const uint8_t *input, int length, uint32_t crc, const uint32_t *table_ptr) {
const uint32_t *current = (const uint32_t *)input;
int remaining = length;
uint32_t(*table)[8][256] = (uint32_t(*)[8][256])table_ptr;
while (remaining >= 8) {
uint32_t c1 = *current++ ^ crc;
uint32_t c2 = *current++;
uint32_t t1 = (*table)[7][c1 & 0xff] ^ (*table)[6][(c1 >> 8) & 0xff] ^ (*table)[5][(c1 >> 16) & 0xff] ^
(*table)[4][(c1 >> 24) & 0xff];
uint32_t t2 = (*table)[3][c2 & 0xff] ^ (*table)[2][(c2 >> 8) & 0xff] ^ (*table)[1][(c2 >> 16) & 0xff] ^
(*table)[0][(c2 >> 24) & 0xff];
crc = t1 ^ t2;
remaining -= 8;
}
return s_crc_generic_sb4(&input[length - remaining], remaining, crc, table_ptr);
}
/* Computes the Castagnoli CRC32c (iSCSI) using one byte at a time, i.e. no slicing. */
static uint32_t s_crc32c_no_slice(const uint8_t *input, int length, uint32_t previousCrc32c) {
return ~s_crc_generic_sb1(input, length, ~previousCrc32c, &CRC32C_TABLE[0][0]);
}
/* Computes the Castagnoli CRC32c (iSCSI) using slice-by-8. */
static uint32_t s_crc32c_sb8(const uint8_t *input, int length, uint32_t previousCrc32) {
uint32_t crc = s_crc_generic_align(&input, &length, ~previousCrc32, &CRC32C_TABLE[0][0]);
return ~s_crc_generic_sb8(input, length, crc, &CRC32C_TABLE[0][0]);
}
/************************************************************************
*
* Calculate CRC-32C (Castagnoli) for the specified input data.
*
* If the host is big endian the calculation is the byte-by-byte, aka,
* slice-by-1, version. Otherwise the calculation utilizes the
* slice-by-8 optimized calculation.
*
* Return the CRC value on success or 0 on error.
************************************************************************/
uint32_t
ms_crc32c (const uint8_t* input, int length, uint32_t previousCRC32C)
{
if (!input || length <= 0)
return 0;
if (ms_bigendianhost())
return s_crc32c_no_slice(input, length, previousCRC32C);
else
return s_crc32c_sb8(input, length, previousCRC32C);
} /* End of ms_crc32c() */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,196 @@
<doxygenlayout version="1.0">
<!-- Generated by doxygen 1.8.14 -->
<!-- Navigation index tabs for HTML output -->
<navindex>
<tab type="mainpage" visible="yes" title="Home"/>
<tab type="pages" visible="no" title="" intro=""/>
<tab type="modules" visible="yes" title="Reference Documentation" intro=""/>
<tab type="namespaces" visible="no" title="">
<tab type="namespacelist" visible="yes" title="" intro=""/>
<tab type="namespacemembers" visible="yes" title="" intro=""/>
</tab>
<tab type="classes" visible="no" title="">
<tab type="classlist" visible="yes" title="" intro=""/>
<tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
<tab type="hierarchy" visible="yes" title="" intro=""/>
<tab type="classmembers" visible="yes" title="" intro=""/>
</tab>
<tab type="files" visible="no" title="">
<tab type="filelist" visible="no" title="" intro=""/>
<tab type="globals" visible="no" title="" intro=""/>
</tab>
<tab type="globals" visible="yes" title="Functions, etc." intro=""/>
<tab type="user" visible="yes" url="@ref page-examples" title="Examples" intro="library examples"/>
<tab type="user" visible="yes" url="@ref page-faq" title="FAQ" intro="FAQ"/>
</navindex>
<!-- Layout definition for a class page -->
<class>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<inheritancegraph visible="$CLASS_GRAPH"/>
<collaborationgraph visible="$COLLABORATION_GRAPH"/>
<memberdecl>
<nestedclasses visible="yes" title=""/>
<publictypes title=""/>
<services title=""/>
<interfaces title=""/>
<publicslots title=""/>
<signals title=""/>
<publicmethods title=""/>
<publicstaticmethods title=""/>
<publicattributes title=""/>
<publicstaticattributes title=""/>
<protectedtypes title=""/>
<protectedslots title=""/>
<protectedmethods title=""/>
<protectedstaticmethods title=""/>
<protectedattributes title=""/>
<protectedstaticattributes title=""/>
<packagetypes title=""/>
<packagemethods title=""/>
<packagestaticmethods title=""/>
<packageattributes title=""/>
<packagestaticattributes title=""/>
<properties title=""/>
<events title=""/>
<privatetypes title=""/>
<privateslots title=""/>
<privatemethods title=""/>
<privatestaticmethods title=""/>
<privateattributes title=""/>
<privatestaticattributes title=""/>
<friends title=""/>
<related title="" subtitle=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<services title=""/>
<interfaces title=""/>
<constructors title=""/>
<functions title=""/>
<related title=""/>
<variables title=""/>
<properties title=""/>
<events title=""/>
</memberdef>
<allmemberslink visible="yes"/>
<usedfiles visible="$SHOW_USED_FILES"/>
<authorsection visible="yes"/>
</class>
<!-- Layout definition for a namespace page -->
<namespace>
<briefdescription visible="yes"/>
<memberdecl>
<nestednamespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<classes visible="yes" title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection visible="yes"/>
</namespace>
<!-- Layout definition for a file page -->
<file>
<briefdescription visible="yes"/>
<includes visible="$SHOW_INCLUDE_FILES"/>
<includegraph visible="$INCLUDE_GRAPH"/>
<includedbygraph visible="$INCLUDED_BY_GRAPH"/>
<sourcelink visible="yes"/>
<memberdecl>
<classes visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<constantgroups visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<functions title=""/>
<variables title=""/>
</memberdef>
<authorsection/>
</file>
<!-- Layout definition for a group page -->
<group>
<briefdescription visible="yes"/>
<groupgraph visible="$GROUP_GRAPHS"/>
<memberdecl>
<nestedgroups visible="yes" title=""/>
<dirs visible="yes" title=""/>
<files visible="yes" title=""/>
<namespaces visible="yes" title=""/>
<classes visible="yes" title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
<membergroups visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
<memberdef>
<pagedocs/>
<inlineclasses title=""/>
<defines title=""/>
<typedefs title=""/>
<enums title=""/>
<enumvalues title=""/>
<functions title=""/>
<variables title=""/>
<signals title=""/>
<publicslots title=""/>
<protectedslots title=""/>
<privateslots title=""/>
<events title=""/>
<properties title=""/>
<friends title=""/>
</memberdef>
<authorsection visible="yes"/>
</group>
<!-- Layout definition for a directory page -->
<directory>
<briefdescription visible="yes"/>
<directorygraph visible="yes"/>
<memberdecl>
<dirs visible="yes"/>
<files visible="yes"/>
</memberdecl>
<detaileddescription title=""/>
</directory>
</doxygenlayout>

@ -0,0 +1,100 @@
#!/bin/bash
# Documentation build directory, relative to script directory
DOCDIR=gh-pages
# Extract version from header
if [[ $(grep LIBMSEED_VERSION ../libmseed.h) =~ LIBMSEED_VERSION[[:space:]]+\"(.*)\"[[:space:]]* ]]; then
PROJECT_VERSION=${BASH_REMATCH[1]}
else
echo "WARNING: Cannot extract version"
fi
# Generate year and date strings
CURRENT_YEAR=$(date -u +%Y)
CURRENT_DATE=$(date -u +%Y-%m-%d)
# Check for command line options
while getopts ":YNP" o; do
case "${o}" in
Y)
PUSHYES=Y
;;
N)
PUSHYES=N
;;
P)
BUILDPDF=Y
;;
*)
echo "Usage: $0 [-Y] [-N] [-P]" 1>&2;
exit 1;
;;
esac
done
shift $((OPTIND-1))
# Build extra options for injection into config
DOXYGENCONFIG+="PROJECT_NUMBER=${PROJECT_VERSION}\n"
DOXYGENCONFIG+="ALIASES+=currentyear='${CURRENT_YEAR}'\n"
DOXYGENCONFIG+="ALIASES+=currentdate='${CURRENT_DATE}'\n"
if [[ "$BUILDPDF" == "Y" ]]; then
DOXYGENCONFIG+="GENERATE_LATEX=YES\n"
fi
# Documentation build command, injecting current project version
DOCBUILD="(cat Doxyfile; echo -e '${DOXYGENCONFIG}') | doxygen -"
# Change to working directory, aka base directory of script
BASEDIR=$(dirname $0)
cd $BASEDIR || { echo "Cannot change-directory to $BASEDIR, exiting"; exit 1; }
# Make clean gh-pages directory
rm -rf $DOCDIR
mkdir $DOCDIR || { echo "Cannot create directory '$DOCDIR', exiting"; exit 1; }
# Build docs
echo "Building docs"
eval $DOCBUILD || { echo "Error running '$DOCBUILD', exiting"; exit 1; }
# Build PDF and copy to current directory
if [[ "$BUILDPDF" == "Y" ]]; then
if [[ -d latex ]]; then
echo "Building PDF"
BUILDPDF=$(cd latex; make pdf 2>&1)
cp latex/refman.pdf libmseed.pdf
else
echo "WARNING: Cannot build PDF, no source latex directory"
fi
fi
GITREMOTE=$(git config --get remote.origin.url)
# Exit if already instructed to not push
if [[ "$PUSHYES" == "N" ]]; then
echo "Exiting without pushing to remote"
exit 0
fi
# Unless pushing already acknowledged ask if docs should be pushed
if [[ "$PUSHYES" != "Y" ]]; then
read -p "Push documentation to gh-pages branch of $GITREMOTE (y/N)? " PUSHYES
if [[ "$PUSHYES" != "Y" && "$PUSHYES" != "y" ]]; then
exit 0
fi
fi
cd $DOCDIR || { echo "Cannot change-directory to $DOCDIR, exiting"; exit 1; }
# Init repo, add & commit files, add remote origin
git init
touch .nojekyll
git add .
git commit -m 'committing documentation'
git remote add origin $GITREMOTE
echo "Pushing contents of $BASEDIR/$DOCDIR to $GITREMOTE branch gh-pages"
git push --quiet --force origin main:gh-pages

@ -0,0 +1,78 @@
/**
@page page-capabilities Capabilities
@tableofcontents
@section overview Overview
This section describes the capabilities and fundamentals of the
library.
@subsection data-records Data Records
@note miniSEED data are constructed as records, typically anywhere
from 128 to 4096 bytes in length. Each record is independent,
identifying the data source, encoding type, etc. in header structures.
Reconstructing a continuous time series from an arbitrary number of
data records is an excersize for a format reader, e.g. this library.
A miniSEED record is represented in the library using the MS3Record
structure. This structure is used for both unpacking and packing of
miniSEED records. When unpacking with msr3_parse() this structure is
populated. When packing with msr3_pack() this structure is used as a
template for the resulting data records and as a source of samples to
be packed.
@subsubsection Data Sample Encodings
The library supports all commonly used @ref encoding-values for
decoding and a subset of the most common values for encoding. The
following data encoding formats are supported for both unpacking and
packing: ASCII, INT16, INT32, FLOAT32, FLOAT64, STEIM1 and STEIM2.
The INT and FLOAT encodings each have two versions for quantities with
a different number of bits of representation. The STEIM compression
encodings work with 32-bit integers. The following data encoding
formats are supported for unpacking only: GEOSCOPE (24-bit, 16/3 and
16/4 gain ranged), CDSN, SRO and DWWSSN.
@subsection traces Traces
In order to reconstruct, manage and process continuous trace segments
the library provides @ref trace-list functionality.
@ref trace-list structures are nested to contain an arbitrary number
of identified time series, each containing an arbitrary number
continuous time series segments, aka traces. While a trace list is
normally used to hold trace information and associated data samples
they can also be used without data samples as a means of tracking data
coverage without actual sample values.
@subsection time-representation Time representation
Internally, time stamps are represented as nanoseconds since the
Unix/POSIX epoch via the nstime_t data type. A number of functions
exist to parse or generate date-time strings to or from this
representation. See @ref time-related.
*Note:* nanosecond time resolution does not mean the data included
this resolution.
@subsection time-series-data Time series data formats
Time series data samples are supported in a few different formats
depending on how they are unpacked or will be packed. Samples can be
either ASCII, 32-bit integer, 32-bit floats or 64-bit double precision
floats. These types are represented internally using the
single-character @ref sample-types.
@subsection log-messages Log messages
All of the log and diagnostic messages emitted by the library
functions use a central logging facility. It is common for programs
that use the library to also use these logging functions.
Furthermore, the output from these logging interfaces can be
controlled by directing output to callback functions. This is useful
when the library will be embedded in a larger system with it's own
logging facility. See the @ref logging page for more details.
*/

@ -0,0 +1,20 @@
.memtitle {
padding-left: 0px;
}
/* Replace content of permalinks */
.permalink a {
color: transparent;
font-size: 0;
}
.permalink a:before {
content: url('https://cdnjs.cloudflare.com/ajax/libs/octicons/8.5.0/svg/link.svg');
visibility: hidden;
padding-right: 2px;
}
/* Show link icon when member title is hovered */
h2.memtitle:hover .permalink a:before {
visibility: visible;
}

@ -0,0 +1,96 @@
/**
@page page-examples Examples
@tableofcontents
@section examples-overview Overview
The most basic usage of the library is illustrated in the @ref
page-tutorial. This page contains full example programs that utilize
the library for common tasks. These examples are included in the
source distribution and (most) are used in the test suite.
While these are full working programs the aspects not related to
library usage, e.g. argument parsing, are often minimized and left
uncommented as they will change in real world usage.
@section example-mseedview Read miniSEED from files
A simple program to read miniSEED from files and print details from
each record:
@include mseedview.c
@section example-lm_read_selection Reading with selections
Read miniSEED with @ref data-selections used to limit what is read.
Additionally, this program reads data into a @ref trace-list and
illustrates traversing the entries.
@include lm_read_selection.c
@section example-lm_read_recordlist Reading with record lists
Read miniSEED a file in 2 passes:
-# Read the file and construct a @ref trace-list without unpacking the
data samples and constructing a @ref record-list
-# Unpack the data samples for each segment individually.
This pattern allows the caller to selectively unpack the data by
segment if desired.
While this example unpacks the data into a buffer allocated by the
library, the unpacking routine mstl3_unpack_recordlist() also allows
data samples to be placed directly into caller-specified memory
buffers.
While this example uses ms3_readtracelist() for reading data from a
file, the same functionality exists in mstl3_readbuffer() for reading
data from a memory buffer.
@include lm_read_recordlist.c
@section example-lm_read_buffer Reading from memory buffers
Read miniSEED from memory buffers. In this case a file is read into a
buffer simply to illustrate reading from a buffer. In practice this
would functionality would be used with data received via a network
connection or some other, non-file, mechanism.
@include lm_read_buffer.c
@section example-lm_pararead Reading files in parallel
Read miniSEED in parallel using re-entrant interfaces and POSIX threading.
@include lm_pararead.c
@section example-lm_pack Writing miniSEED
An example of creating miniSEED. Static data with known signal is
used for input for illustration and testing.
@include lm_pack.c
@section example-lm_pack_rollingbuffer Writing miniSEED with rolling buffer
An example of creating miniSEED using a ::MS3TraceList as a rolling
buffer of data. This pattern is useful for generating miniSEED in a
streaming fashion for scenarios where holding all data in memory is
not possible or practical. For example, very large data sets or
continuous, streaming data.
An input file of miniSEED is used as a convenient data source.
::MS3Record containers can be constructed for any arbitrary data and
follow the same pattern of record generation.
@include lm_pack_rollingbuffer.c
@section example-lm_sids Working with Source Identifiers
An example of mapping between source identifiers (SIDs) and SEED
identifier codes.
@include lm_sids.c
*/

@ -0,0 +1,110 @@
/**
@page page-faq Frequency asked questions
@tableofcontents
@section faq-list FAQs
@subsection faq-1 How do I read/write data from/to files?
The short answer is to use ms3_readmsr(), ms3_readtracelist(), and ms3_writemsr().
You can find descriptions and code examples in the @ref page-tutorial and @ref page-examples sections.
@subsection faq-2 Can I read/write data from/to memory buffers?
Yes! Use msr3_parse() to read data from a memory buffer, and msr3_pack() to write data to a memory buffer.
The msr3_pack() function accepts a callback function that is called when records are completed, from there
the caller can do whatever is desired with the record.
@subsection faq-3 How do I read data from a URL?
The library includes support for reading from URLs using <a class="el" href="https://curl.se/libcurl/">libcurl</a>.
To use this feature, the library must be compiled with **LIBMSEED_URL** defined, and the program must be
linked with both this library and libcurl.
The stream/file reading functions in the library will automatically detect URLs versus local files
and there is no need to do anything special to use this feature.
Specifics of the URL support can be configured with @ref ms3_url_useragent(), @ref ms3_url_userpassword(),
and @ref ms3_url_addheader().
To disable TLS/SSL peer and host verification set the **LIBMSEED_SSL_NOVERIFY** environment variable.
@subsection faq-4 miniSEED is simple, why is a library needed?
Indeed, a major advantage of miniSEED is that it is relatively simple. In specific cases, reading
and even writing of miniSEED can a implemented with very little code. However, there are many
combinations possible in record construction, data encodings, record lengths, proper time determination,
endianess, etc. which make the general case non-trivial. With 2 versions of the format that are not
binary compatible, the general case becomes even more complex.
<em>Importantly</em>, the library handles the task of re-assembling continuous time series data from independent,
and arbitrarily organized, miniSEED records. This "beyond miniSEED" support no small task, and is required
for most use cases.
Furthermore, the library contains optimizations for handling large volumes and highly-multiplexed data,
as well efficiently dealing with historical quirks and data problems.
@subsection faq-5 Can I use libmseed strictly with miniSEED version 2?
Yes. The library is backwards compatible with miniSEED version 2, and will automatically detect the
version of data being read. Version 2 records can be created by setting the @ref MSF_PACKVER2 flag
when calling the pack or write functions.
@subsection faq-6 I need to use separate FDSN identifiers of Network, Station, Location and Channel.
<em>and what is the deal with this new Source Identifier?</em>
In 2020 the FDSN approved the <a class="el" href="https://docs.fdsn.org/projects/source-identifiers">Source Identifier</a>
specification to overcome the limitations of <a class="el" href="https://fdsn.org/pdf/SEEDManual_V2.4.pdf">SEED</a>
network, station, location, and channel codes.
In particular length limitations, instrument-type code depletion, and provide a standard way to combine them.
This specification is a superset of SEED codes and is backwards compatible as long as the codes are short
enough to fit into SEED limitations.
As of major version 3, the library adopted the FDSN Source Identifer, often abbreviated to \a SID, replacing
the previous representation that was very similar.
You can use the @ref ms_sid2nslc() and @ref ms_nslc2sid() routines to convert between the two representations.
Except for potentially larger individual codes, the major difference in the two representations is the
\a channel code. In the SEED specification this is a fixed 3-character code, while in the FDSN Source Identifier
specification the channel is 3 codes separated by underscores, with each code potentially being larger than a
single character. The library is agnostic to form of a channel representation, accepting either and converting
between them whenever possible and appropriate.
@subsection faq-7 The library API changed! Why? How do I port my libmseed 2.x program to the 3.x API?
Starting with major version 3 of the library the internal data model was changed to be based on miniSEED format
version 3. This relatively large structural change required API changes, and the opportunity was taken To
improve the API in other ways.
See the @ref porting-guide.
@subsection faq-8 I'm using the library and would like to cite it. How do I do that?
A publication is planned and will be added here when available.
For now, please cite the GitHub repository: https://github.com/EarthScope/libmseed
Thank you!
@subsection faq-9 This library sucks. What can I do?
It won't be everyone's cup of tea. Some alternative libraries are:
P. Crotwell's <a class="el" href="https://www.seis.sc.edu/seisFile.html">SeisFile</a> - Java library with miniSEED support.
D. Neuhauser's <a class="el" href="https://www.ncedc.org/qug/software/ucb/">Qlib2</a> - C library with miniSEED support.
(happy to add more here, please let me know!)
@subsection faq-10 This library is great, but doesn't do something I need. What can I do? How can I contribute?
Contributions of ideas, problems reports, and code are welcome!
Please <a class="el" href="https://github.com/EarthScope/libmseed/issues">post issues</a> to the repository.
Code contributions are best submitted as <a class="el" href="https://github.com/EarthScope/libmseed/pulls">pull requests</a>.
*/

File diff suppressed because one or more lines are too long

@ -0,0 +1,77 @@
/**
@mainpage libmseed Documentation
@section Overview
The miniSEED library provides a framework for manipulation of miniSEED
records, a format commonly used for seismological time series and
related data. The library includes the functionality to read and
write data records, in addition to reconstructing time series from
multiple records.
The library should work in Unix-like, Windows and potentially other
environments.
@subsection main-tutorial Getting started
The @subpage page-tutorial contains an overview of basic usage and
examples to get you going.
The @subpage page-capabilities page provides an overview the data format
fundamentals and capabilities of the library.
@subsection main-downloding Downloading and installing
The <a class="el" href="https://github.com/earthscope/libmseed/releases">releases</a>
area contains release versions.
For installation instructions see the
<a class="el" href="https://github.com/earthscope/libmseed/tree/master/INSTALL.md">INSTALL</a>
file.
@subsection develop-main Development and issues
Please report <a class="el" href="https://github.com/earthscope/libmseed/issues">issues</a>
to the project.
If you would like to contribute to the project please file Pull Requests
and/or create issues for discussion at the <a class="el" href="https://github.com/earthscope/libmseed/">
libmseed project</a>.
@subsubsection porting-main Porting from earlier version of the library
A @ref porting-guide is available for developer porting software that
previously used version 2 of the library.
@subsection versioning-main Versioning
Releases are versioned using <a class="el" href="http://semver.org/">Semantic Versioning</a>.
@subsection main-acknowledgements Acknowlegements
Numerous improvements have been incorporated based on feedback and
patches submitted by others. Individual acknowlegements are included
in the ChangeLog and/or commit messages. Contributions are welcome and greatly appreciated.
This library also uses code bits published in the public domain and
acknowledgement is included in the code whenever possible.
@subsection main-license License
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this software except in compliance with the License.
You may obtain a copy of the License at
<a class="el" href="http://www.apache.org/licenses/LICENSE-2.0">
http://www.apache.org/licenses/LICENSE-2.0</a>
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
Copyright (C) @currentyear Chad Trabant, EarthScope Data Services
Documentation last generated @currentdate
*/

@ -0,0 +1,179 @@
/**
@page porting-guide Guide for porting from earlier libmseed versions
@tableofcontents
@section porting-overview Overview and approach
This page contains a description of major API changes from version 2
to 3 of the library.
The recommended approach to porting is as follows:
-# Read through the @ref porting-important, changing anything
in the calling program that is obvious.
-# Try compiling the target program with the new library and fix any
identified problems.
-# Read @ref porting-other to understand other changes that may not be
identified at compile time but may yet effect the program.
@subsection porting-important Most important changes that commonly need attention
- Convert \c MSRecord structure type usage to ::MS3Record, which has
similar (but not the same) members.
- Convert \c MSTraceList, \c MSTraceID, and \c MSTraceSeg structure
types usage to ::MS3TraceList, ::MS3TraceID, and ::MS3TraceSeg, which
have similar (but not the same) members.
- Convert usage of MSTraceGroups to ::MS3TraceList. Legacy "Trace Groups"
are no longer supported. The @ref page-examples page contains examples
of using @ref trace-list functionality.
- MS3TraceList.numtraces renamed to ::MS3TraceList.numtraceids.
- The \c fpos and \c last arguments of ::ms3_readmsr(), ::ms3_readmsr_r(),
and ::ms3_readmsr_selection() have been removed. The same capability is
available using the re-entrant ('_r') functions with ::MS3FileParam (msfp)
- Stream/file position of returned record is (msfp->streampos - msr->reclen)
- Starting position of a read can be set at \c msfp->startoffset
- The last record read is identified by the return value of ::MS_ENDOFFILE
- Convert all \c hptime_t typed variables to \c nstime_t type.
@note the \c nstime_t type is a nanosecond epoch value, whereas the
previous \c hptime_t was a microsecond epoch value. Careful review is
required for values used by a program directly (they really _should
not_ be).
- Review and change functions with \c hptime in the name to their
closest equivalent for the new \c nstime version. See @ref time-related.
- Change all usage of \c ms_hptime2isotimestr(), \c ms_hptime2mdtimestr(),
and \c ms_hptime2seedtimestr() functions to use ms_nstime2timestr(), which
has enumerated flags to specify the time string format. In general:
- ms_hptime2isotimestr() becomes ms_nstime2timestr(nstime, timestr, ISOMONTHDAY, subsecond)
- ms_hptime2mdtimestr() becomes ms_nstime2timestr(nstime, timestr, ISOMONTHDAY_SPACE, subsecond)
- ms_hptime2seedtimestr() becomes ms_nstime2timestr(nstime, timestr, SEEDORDINAL, subsecond)
- The _time format_ and _subseconds_ flags have changed from integers
to \c enum values, review and change calling of \c
ms_nstime2timestr(), \c mstl3_printtracelist(), \c
mstl3_printsynclist(), and \c mstl3_printgaplist().
@note If the above functions are simply renamed and the flag values
are not changed to use the enumerated types, leaving integers as
arguments, there may be a **non-obvious bug**. Most compilers will
quiety accept an integer for the enum argument, which may or may not
match the desired time format or subsecond handling. Assume _not_.
- Adapt to new identification of a record source. The channel
identification has changed from \c NN_SSS_LL_CHA, commonly printed in
library console output and logging, to a URI-style Source Identifier
(SID) with the pattern \c FDSN:NN_SSS_LL_B_S_s. The following helper
functions are available for mapping between the new URI-based scheme
and the traditional SEED network, station, location, channel scheme:
- ms_sid2nslc(): convert SID to traditional SEED identifiers
- ms_nslc2sid(): convert traditional SEED identifiers to an SID
- ms_seedchan2xchan(): convert SEED channel to SID-style channel components
- ms_xchan2seedchan(): convert SID band, source and position to SEED channel
- The new data model allows sampling rate to be specified in samples/second
(Hertz) or sampling period (seconds). This is represented in the \a
samprate values, such as ::MS3Record.samprate, as follows:
- \c samprate >= 0.0 is a rate in samples/second (Hertz)
- \c samprate < 0.0 is a (negated) sampling period in seconds
It is common that rates equal to or greater than 1 Hz are represented
in samples/second and rates less than 1 Hz are represented as a
period.
Applications that must consistently have access to the samples/second
representation may use the msr3_sampratehz() function.
@subsection porting-other Other changes that may need attention
- The supported range for the internal time scale is reduced from year
5000 to year 2262 (due to the change in time resolution). If an
application previously used the library with years beyond 2262, such
programs should be adapted for this new limit.
- The \c off_t type is no longer used by the library due to
non-portable, inconsistent size. Instead, the \c int64_t type is
used. Calling programs should adjust their usage accordingly. The
API changed as follows:
- The global LM_SIZEOF_OFF_T is removed, no longer needed
- The type of \a fpos (file position) arument of ms3_readmsr(), ms3_readmsr_r(), and ms3_readmsr_selection() has changed
- Some internal functions and structures rarely used by callers were changed
- The \c flag typedef is now legacy, you may wish to convert to directly using int8_t
- The time and sample rate tolerances, specified as \c timetol and
\c sampratetol arguments, have been replaced with ::MS3Tolerance which
identifies callback functions that return tolerances for a specified ::MS3Record.
- The SEED 2.x data quality identifiers no longer exist in the new data model.
The library maps these values to integer publications versions as follows:
- Quality \b R => \b 1
- Quality \b D => \b 2
- Quality \b Q => \b 3
- Quality \b M => \b 4
- Unknown quality => \b 0
- For applications that need access to flags in the miniSEED 2.x fixed
header, they have moved to the following locations:
- Activity flags (field 12):
- Bit 0 (calibration signals present) => Fixed header flags, bit 0
- Bit 1 (time correction applied), not retained
- Bit 2 (begining of event) => Extra header FDSN.Event.Begin
- Bit 3 (end of event) => Extra header FDSN.Event.End
- Bit 4 (positive leap second included) => Extra header FDSN.Time.LeapSecond
- Bit 5 (negative leap second included) => Extra header FDSN.Time.LeapSecond
- Bit 6 (event in progress) => Extra header FDSN.Event.InProgress
- I/O flags (field 13):
- Bit 0 (Station volume parity error) => Extra header FDSN.Flags.StationVolumeParityError
- Bit 1 (Long record read) => Extra header FDSN.Flags.LongRecordRead
- Bit 2 (Short record read) => Extra header FDSN.Flags.ShortRecordRead
- Bit 3 (Start of time series) => Extra header FDSN.Flags.StartOfTimeSeries
- Bit 4 (End of time series) => Extra header FDSN.Flags.EndOfTimeSeries
- Bit 5 (Clock locked) => Fixed header flags, bit 2
- Data quality flags (field 14):
- Bit 0 (Amplifier saturation detected) => Extra header FDSN.Flags.AmplifierSaturation
- Bit 1 (Digitizer clipping detected) => Extra header FDSN.Flags.DigitizerClipping
- Bit 2 (Spikes detected) => Extra header FDSN.Flags.Spikes
- Bit 3 (Glitches detected) => Extra header FDSN.Flags.Glitches
- Bit 4 (Missing/padded data present) => Extra header FDSN.Flags.MissingData
- Bit 5 (Telemetry synchronization error) => Extra header FDSN.Flags.TelemetrySyncError
- Bit 6 (Digital filter may be charging) => Extra header FDSN.Flags.FilterCharging
- Bit 7 (Time tag questionable) => Fixed header flags, bit 1
The existence of these boolean extra header values can be tested with mseh_exists().
@subsection porting-data-model-change Ramifications for change in data model
With an internal change in the data model, from miniSEED 2 to
version 3, results in the following consequences:
- Version 2.x data quality indicators (D, R, Q and M) are no longer
supported. These are mapped to version 3 publication versions.
- Version 2.x beam blockettes (400 & 405) are no longer supported,
they will be dropped if reading records that contain such
blockettes.
- Version 2.x opaque blockettes (2000) are no longer supported, they
will be dropped if reading records that contain such blockettes.
Note that the format version 3 @ref extra-headers functionality can
be used to contain most arbitrary data.
- Version 2.x timing blockettes (500) contain one "Clock Model"
designation per blockette, potentially allowing for multiple
designations in a single record. Upon reading such a record, only
the last clock model is retained (in the \c FDSN.Clock.Model @ref
extra-headers).
- Version 2.x sequence numbers, as six digit ASCII string, are not
retained. In the new format these values may be placed in @ref
extra-headers by a calling program as desired.
*/

@ -0,0 +1,191 @@
/**
@page page-tutorial Tutorial
@tableofcontents
@section common-usage Common usage
This page contains a description of basic library usage for the most
common usage cases.
Additionally, the @ref page-examples page contains full examples for
common use cases, which are also included in the 'examples' directory
of the source code distribution.
@subsection reading Reading miniSEED data
A common task is to read a file of miniSEED records and perform some
action based on the header values or apply some process to the data
samples. There are two patterns to support this in the library, one
to iterate over the file record-by-record and another to read all data
into a collection of continuous series.
@subsubsection reading-records Reading miniSEED records from files
The ms3_readmsr() routine will open a specified file and return
MS3Record structures for each miniSEED record it reads from the file.
Called iteratively in a loop, all records are returned in the order
discovered.
A code snippet for reading miniSEED from a file record-by-record:
@anchor msr3-readmsr-snippet
@code
int main ()
{
char *filename = "datafile.mseed";
MS3Record *msr = NULL;
uint32_t flags = MSF_SKIPNOTDATA & MSF_UNPACKDATA;
int verbose = 0;
int retcode;
while ((retcode = ms3_readmsr (&msr, filename, flags, verbose)) == MS_NOERROR)
{
/* Do something with the record here, e.g. print */
msr3_print (msr, verbose);
}
if (retcode != MS_ENDOFFILE)
ms_log (2, "Cannot read %s: %s\n", filename, ms_errorstr (retcode));
/* Cleanup memory and close file */
ms3_readmsr (&msr, NULL, flags, verbose);
return 0;
}
@endcode
It is important to call ms3_readmsr() for cleanup as illustrated to
free memory and close files.
There are more advanced versions of this routine. The ms3_readmsr_r()
function is a thread-safe version that can be used in threaded
programs to read files in parallel. The ms3_readmsr_selection()
function is a thread-safe version that can additionally accept @ref
data-selections to efficiently return only selected data.
@subsubsection reading-tracelists Reading miniSEED from files into traces lists
Another option is to read all miniSEED into a @ref trace-list without
any handling of records. This is done with ms3_readtraces(), which is
very useful for quickly reading data for processing. The data are
returned in ordered, continuous segments ready for processing.
A code snippet for reading miniSEED from a file into a @ref trace-list :
@anchor msr3-readtracelist-snippet
@code
int main ()
{
char *filename1 = "datafile1.mseed";
char *filename2 = "datafile2.mseed";
MS3TraceList *mstl = NULL;
MS3Tolerance tol = MS3Tolerance_INITIALIZER;
uint32_t flags = MSF_SKIPNOTDATA & MSF_UNPACKDATA;
int verbose = 0;
int retcode;
retcode = ms3_readtracelist (&mstl, filename1, &tol, 0, flags, verbose);
if (retcode != MS_NOERROR)
ms_log (2, "Cannot read %s: %s\n", filename1, ms_errorstr (retcode));
retcode = ms3_readtracelist (&mstl, filename2, &tol, 0, flags, verbose);
if (retcode != MS_NOERROR)
ms_log (2, "Cannot read %s: %s\n", filename2, ms_errorstr (retcode));
if (!mstl)
{
fprintf (stderr, "Error reading file\\n");
return -1;
}
/* Do something with the traces here, e.g. print */
mstl3_printtracelist (mstl, 0, verbose, 0, 0);
mstl3_free (&mstl, 1);
return 0;
}
@endcode
There are more advanced versions of this routine. The
ms3_readtracelist_timewin() function allows data to be limited to a
specific time range while reading. The ms3_readtracelist_selection()
can additionally accept @ref data-selections to efficiently return
only selected data.
@subsubsection reading-buffers Reading miniSEED from memory
If an application is not designed to read miniSEED from files the
library provides functions functionality to read data from memory.
The mstl3_readbuffer() function will read all data from a buffer into
a @ref trace-list. The low-level functions ms3_detect() and
msr3_parse() can be used to detect and parse miniSEED records in
memory buffers.
@subsection writing Writing miniSEED records
Another common task is to create miniSEED records. There are two
patterns to support this in the library: one is to write data from
library containers to files and another to create records and provide
them back to the caller in a memory buffer via a callback function.
@subsubsection callback Callback design
If not writing directly to files, the packing interfaces use a
callback design, where the caller specifies a function that will be
called for every record that is created. It is the responsibility of
the callback function to handle the record before returning. This
design allows a program to do whatever is needed with generated
miniSEED, i.e. write to files, send over the network, or even
injection of more information.
@subsubsection writing-files Writing miniSEED data to files
The library supports writing miniSEED directly to files from either
MS3Record or MS3TraceList containers using msr3_writemseed() or
mstl3_writemseed() respectively.
A code snippet for writing miniSEED to a file from an MS3Record using msr3_writemseed():
@anchor msr3-writemseed-snippet
@code
int main()
{
int packedrecords;
int verbose = 0;
char *msfile = "output.mseed";
int32_t datasamples[] = {0,1,2,3,4,5,6,7,8,9,10};
MS3Record *msr;
msr = msr3_init (NULL);
/* Populate MS3Record values */
strcpy (msr->sid, "XX_TEXT__B_H_E");
msr->formatversion = 3;
msr->reclen = 512;
msr->encoding = DE_STEIM2;
msr->starttime = ms_timestr2nstime ("2018-12-01T00:00:00.000000000");
msr->samprate = 20.0;
msr->datasamples = datasamples; /* pointer to 32-bit integer data samples */
msr->numsamples = 11;
msr->sampletype = 'i'; /* declare data type to be 32-bit integers */
/* Write all data in MS3Record to output file, using MSF_FLUSHDATA flag */
packedrecords = msr3_writemseed (msr, msfile, 1, MSF_FLUSHDATA, verbose);
ms_log (0, "Wrote %d records to %s\n", packedrecords, msfile);
/* Disconnect datasamples pointer, otherwise msr3_free() will attempt to free() it */
msr->datasamples = NULL;
msr3_free (&msr);
}
@endcode
@subsubsection creating-records Creating miniSEED records
Records can be generated from data in either MS3Record or MS3TraceList
containers using, respectively, msr3_pack() or and mstl3_pack().
*/

@ -0,0 +1,49 @@
# Build environment can be configured the following
# environment variables:
# CC : Specify the C compiler to use
# CFLAGS : Specify compiler options to use
# Automatically configure URL support if libcurl is present
# Test for curl-config command and add build options if so
ifneq (,$(shell command -v curl-config))
export LM_CURL_VERSION=$(shell curl-config --version)
export CFLAGS:=$(CFLAGS) -DLIBMSEED_URL
export LDFLAGS:=$(LDFLAGS) $(shell curl-config --libs)
endif
# Required compiler parameters
CFLAGS += -I..
LDFLAGS += -L..
LDLIBS := -lmseed $(LDLIBS)
# Build all *.c source as independent programs
SRCS := $(sort $(wildcard *.c))
BINS := $(SRCS:%.c=%)
.PHONY: all
.NOTPARALLEL: all
all: libmseed $(BINS)
.PHONY: libmseed
libmseed:
@if [ ! -z "$(LM_CURL_VERSION)" ]; then \
echo "Configured with $(LM_CURL_VERSION)"; \
fi
$(MAKE) -C .. $(MAKECMDGOALS)
# Build programs and check for executable
$(BINS) : % : %.c
@printf 'Building $<\n';
$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LDLIBS)
.PHONY: clean
clean:
@rm -rf *.o $(BINS) *.dSYM
.PHONY: install
install:
@echo
@echo "No install target, copy the executable(s) as needed"
@echo

@ -0,0 +1,28 @@
#
# Nmake file for libmseed examples - MS Visual C/C++
# Use 'nmake -f Makefile.win'
INCS = /I..
LIBS = ../libmseed.lib
OPTS = /O2 /D_CRT_SECURE_NO_WARNINGS
SRCS = lm_pack.c \
lm_pack_rollingbuffer.c \
lm_parse.c \
lm_read_buffer.c \
lm_read_recordlist.c \
lm_read_selection.c \
lm_sids.c \
lm_timestr.c \
mseedview.c
BINS = $(SRCS:.c=.exe)
all: $(BINS)
.c.exe:
$(CC) /nologo $(CFLAGS) $(INCS) $(OPTS) $(LIBS) $<
# Clean-up directives
clean:
-del *.obj *.exe *% *~

@ -0,0 +1,8 @@
Documentation of the libmseed interfaces can be found in the 'doc'
directory.
Unix: the Makefile should work for most systems, try 'make'.
Win32: the Makefile.win is for Microsoft's nmake, try
'nmake -f Makefile.win'

@ -0,0 +1,353 @@
/***************************************************************************
* A program for libmseed packing tests.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <libmseed.h>
#define VERSION "[libmseed " LIBMSEED_VERSION " example]"
#define PACKAGE "lm_pack"
static flag verbose = 0;
static int reclen = -1;
static int encoding = 10;
static int msformat = 3;
static char *outfile = NULL;
static int parameter_proc (int argcount, char **argvec);
static void usage (void);
/****************************************************************************
* An expanding sinusoid of 500 samples.
*
* When truncated to integers:
* - Signed differences in samples needing all bit lengths 3-31s.
* - ONLY the last difference requires 31 bits, all others are <= 30
* - Contain sequences of differences matching all Steim 1 and 2 encoding possibilities
*
* Values 1 through up to 220 do not require more than 16-bits.
***************************************************************************/
#define SINE_DATA_SAMPLES 500
static float fsinedata[SINE_DATA_SAMPLES] =
{0.000000,6.109208,10.246826,10.609957,6.764728,-0.075704,-7.409461,-12.346208,
-12.731430,-8.062958,0.182060,8.985442,14.875067,15.276420,9.609196,-0.328370,
-10.895428,-17.921131,-18.329336,-11.450576,0.526448,13.209973,21.590023,21.991385,
13.643140,-0.791247,-16.014492,-26.008907,-26.383901,-16.253504,1.141655,19.412378,
31.330871,31.652348,19.360848,-1.601465,-23.528777,-37.740204,-37.971107,-23.059260,
2.200591,28.515156,45.458753,45.549217,27.460529,-2.976569,-34.554817,-54.753559,
-54.637244,-32.697448,3.976416,41.869576,65.946052,65.535525,38.927729,-5.258928,
-50.727832,-79.423116,-78.604029,-46.338644,6.897516,61.454325,95.650397,94.274177,
55.152523,-8.983716,-74.441929,-115.188314,-113.063003,-65.633259,11.631511,
90.165916,138.711322,135.590105,78.094013,-14.982665,-109.201193,-167.031082,
-162.597954,-92.906331,19.213290,132.243134,201.124338,194.976222,110.510935,
-24.541940,-160.132765,-242.166440,-233.790899,-131.430478,31.239561,193.887193,
291.571675,280.319178,156.284630,-39.641741,-234.736391,-351.041770,-336.091216,
-185.807912,50.163757,284.167632,422.624233,402.940140,220.870763,-63.319072,
-343.979194,-508.782510,-483.061913,-262.504429,79.742042,416.345244,612.480366,
579.087014,311.930343,-100.215795,-503.894220,-737.283353,-694.166245,-370.594813,
125.706429,609.803540,887.480834,832.073438,440.209940,-157.404955,-737.913996,
-1068.232708,-997.328409,-522.801872,196.778712,892.867950,1285.745847,1195.344115,
620.767701,-245.634371,-1080.276240,-1547.486227,-1432.602775,-736.942489,
306.195102,1306.919790,1862.433994,1716.866654,874.678227,-381.195062,-1580.993078,
-2241.390126,-2057.430298,-1037.936774,473.995052,1912.398180,2697.345105,2465.422369,
1231.399220,-588.724017,-2313.099844,-3245.922143,-2954.166800,-1460.594493,
730.452133,2797.554253,3905.910007,3539.614901,1732.050527,-905.402443,-3383.226729,
-4699.903513,-4240.862333,-2053.471832,1121.209554,4091.216806,5655.073452,
5080.767553,2433.947965,-1387.235765,-4947.012887,-6804.092030,-6086.691631,
-2884.198121,1714.957253,5981.403297,8186.245216,7291.383170,3416.857907,-2118.435721,
-7231.576094,-9848.769674,-8734.036728,-4046.815355,2614.894255,8742.446660,
11848.459577,10461.558685,4791.604321,-3225.420222,-10568.260176,-14253.597692,
-12530.081077,-5671.864737,3975.823020,12774.525771,17146.276092,15006.771888,
6711.880612,-4897.680529,-15440.350897,-20625.184991,-17971.999652,-7940.208402,
6029.615451,18661.258563,24808.964001,21521.921578,9390.410233,-7418.851697,
-22552.587165,-29840.229074,-25771.577789,-11101.908663,9123.111793,27253.593143,
35890.411153,30858.590420,13120.982075,-11212.929535,-32932.401520,-43165.569941,
-36947.585456,-15501.922592,13774.468128,39791.979238,51913.378983,44235.478131,
18308.381438,-16912.953578,-48077.342225,-62431.517747,-52957.790070,-21614.930138,
20756.856764,58084.250586,75077.753677,63396.198979,25508.869716,-25462.986446,
-70169.698634,-90282.054065,-75887.560674,-30092.324242,31222.690356,84764.569627,
108561.135815,90834.689747,35484.659605,-38269.404043,-102388.901147,-130535.943080,
-108719.240618,-41825.273267,46887.838631,123670.298781,156952.641109,130117.096987,
49276.805933,-57425.161274,-149366.146307,-188707.832667,-155716.756615,-58028.831480,
70304.598043,180390.393831,226878.845103,186341.292651,68302.086980,-86041.981200,
-217845.865904,-272760.106197,-222974.585037,-80353.310040,105265.874749,
263063.225186,327906.831053,266792.649626,94480.755768,-128742.047924,-317647.960457,
-394187.487304,-319201.052420,-111030.470003,157403.231090,383537.048821,
473846.799900,381879.586964,130403.398591,-192385.288422,-463067.280664,
-569581.409624,-456835.620147,-153063.413757,235071.184227,559057.643966,
684630.722900,546467.782541,179546.337116,-287144.413901,-674908.656359,-822885.998573,
-653642.002301,-210470.033463,350653.927224,814722.125712,989021.327043,781782.266485,
246545.638548,-428093.004245,-983445.533844,-1188650.888674,-934978.952245,
-288589.965744,522495.068481,1187046.097893,1428517.756157,1118118.116795,
337539.108116,-637550.058001,-1432720.599829,-1716720.558561,-1337035.786123,
-394463.210730,777745.745791,1729148.322568,2062985.588205,1598702.057951,
460582.328770,-948539.335064,-2086795.934450,-2478993.447111,-1911440.758239,
-537283.204837,1156565.787585,2518284.974613,2978771.147961,2285191.490698,
626136.686773,-1409890.715316,-3038834.772892,-3579162.765425,-2731822.228828,
-728915.356799,1718317.328563,3666796.264850,4300394.349825,3265502.159830,
847610.742696,-2093758.948552,-4424295.326464,-5166751.952850,-3903146.346575,
-984449.218292,2550691.033230,5338008.063395,6207395.378498,4664945.984099,
1141905.356234,-3106699.622013,-6440095.078674,-7457334.785992,-5575000.657492,
-1322711.048944,3783146.686785,7769327.268660,8958602.684417,6662072.138144,
1529858.136359,-4605977.214406,-9372442.351616,-10761660.350202,-7960482.979376,
-1766591.537123,5606698.099533,11305779.346088,12927085.482769,9511187.602536,
2036388.930375,-6823565.288237,-13637247.864482,-15527597.247686,-11363048.833756,
-2342921.824577,8303023.316062,16448700.704063,18650486.048610,13574359.117581,
2689991.311114,-10101450.710498,-19838792.204081,-22400528.788313,-16214653.084049,
-3081429.850680,12287276.018778,23926421.676653,26903486.467518,19366867.002831,
3520957.976311,-14943542.889821,-28854881.491245,-32310300.258257,-23129911.185536,
-4011981.690190,18171019.183242,34796853.797034,38802125.311214,27621733.908111,
4557312.422997,-22091965.102165,-41960429.245394,-46596369.274924,-32982970.290335,
-5158786.517383,26854699.579994,50596356.438136,55953935.730766,39381287.228525,
5816755.047390,-32639133.476996,-61006773.393892,-67187912.573574,-47016556.451947,
-6529407.091211,39663473.627686,73555723.560159,80673993.102082,56127012.680548,
7291879.963058,-48192344.715084,-88681820.564997,-96862974.793882,-66996583.433046,
-8095097.920129,58546627.892657,106913500.120816,116295749.303753,79963612.136585,
8924265.924556,-71115377.915425,-128887386.814358,-139621279.391140,
-95431237.847443,-9756926.457174,86370256.557591,155370411.011265,167618156.945886,
113879744.320966,10560464.285645,-104883012.041142,-187286440.462195,
-201220454.267134,-135881249.803956,-11288915.420918,127346645.407973,
225748346.861610,241548722.121826,162117178.463787,11878900.943144,
-154601039.263161,-272096614.921471,-289947157.492990,-193399036.824020,
-12244462.331299,187663986.962885,327945826.905572,348028166.863781,
230693116.321629,12270520.408649,-227768756.995135,-395240626.753420,
-417725794.004062,-275149858.943091,-11804612.586023,276409565.108355,
476323094.198962,501359772.474058,328138760.150134,10646479.758475,
-335396614.264246,-574013851.836865,-601712311.942546,-391289845.886545,
-8534971.317913,406922710.094078,691709700.348455,722120145.317499,
466542952.987464,5131609.783276,-493643879.751773,-833501145.234545,
-866584864.231526,-556206270.243475,0.00000};
static char *textdata =
"I've seen things you people wouldn't believe. Attack ships on fire off the shoulder of Orion. "
"I watched C-beams glitter in the dark near the Tannhäuser Gate. All those moments will be lost "
"in time, like tears...in...rain. Time to die.";
/* Binary I/O for Windows platforms */
#ifdef LMP_WIN
#include <fcntl.h>
unsigned int _CRT_fmode = _O_BINARY;
#endif
int
main (int argc, char **argv)
{
MS3Record *msr = NULL;
uint32_t flags = 0;
int32_t sinedata[SINE_DATA_SAMPLES];
double dsinedata[SINE_DATA_SAMPLES];
int idx;
int rv;
/* Create integer and double sine data sets */
for (idx = 0; idx < SINE_DATA_SAMPLES; idx++)
{
sinedata[idx] = (int32_t)(fsinedata[idx]);
dsinedata[idx] = (double)(fsinedata[idx]);
}
/* Process command line arguments */
if (parameter_proc (argc, argv) < 0)
return -1;
if (!(msr = msr3_init (msr)))
{
ms_log (2, "Could not allocate MS3Record, out of memory?\n");
return -1;
}
/* Set up record parameters */
strcpy (msr->sid, "FDSN:XX_TEST__X_Y_Z");
msr->reclen = reclen;
msr->pubversion = 1;
msr->starttime = ms_timestr2nstime ("2012-01-01T00:00:00");
msr->samprate = 1.0;
msr->encoding = encoding;
if (encoding == DE_TEXT)
{
msr->numsamples = strlen (textdata);
msr->datasamples = textdata;
msr->sampletype = 't';
}
else if (encoding == DE_FLOAT32)
{
msr->numsamples = SINE_DATA_SAMPLES;
msr->datasamples = fsinedata;
msr->sampletype = 'f';
}
else if (encoding == DE_FLOAT64)
{
msr->numsamples = SINE_DATA_SAMPLES;
msr->datasamples = dsinedata;
msr->sampletype = 'd';
}
else if (encoding == DE_INT16)
{
msr->numsamples = 220; /* The first 220 samples can be represented in 16-bits */
msr->datasamples = sinedata;
msr->sampletype = 'i';
}
else if (encoding == DE_INT32)
{
msr->numsamples = SINE_DATA_SAMPLES;
msr->datasamples = sinedata;
msr->sampletype = 'i';
}
else if (encoding == DE_STEIM1)
{
msr->numsamples = SINE_DATA_SAMPLES;
msr->datasamples = sinedata;
msr->sampletype = 'i';
}
else if (encoding == DE_STEIM2)
{
msr->numsamples = SINE_DATA_SAMPLES - 1; /* Steim-2 can represent all but the last difference */
msr->datasamples = sinedata;
msr->sampletype = 'i';
}
else
{
ms_log (2, "Unsupported encoding: %d\n", encoding);
return -1;
}
msr->samplecnt = msr->numsamples;
/* Set data flush flag */
flags |= MSF_FLUSHDATA;
/* Set miniSEED v2 if requested */
if (msformat == 2)
flags |= MSF_PACKVER2;
rv = msr3_writemseed (msr, outfile, 1, flags, verbose);
if (rv < 0)
ms_log (2, "Error (%d) writing miniSEED to %s\n", rv, outfile);
/* Make sure everything is cleaned up */
msr->datasamples = NULL;
msr3_free (&msr);
return 0;
} /* End of main() */
/***************************************************************************
* parameter_proc:
*
* Process the command line arguments.
*
* Returns 0 on success, and -1 on failure
***************************************************************************/
static int
parameter_proc (int argcount, char **argvec)
{
int optind;
/* Process all command line arguments */
for (optind = 1; optind < argcount; optind++)
{
if (strcmp (argvec[optind], "-V") == 0)
{
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
exit (0);
}
else if (strcmp (argvec[optind], "-h") == 0)
{
usage ();
exit (0);
}
else if (strncmp (argvec[optind], "-v", 2) == 0)
{
verbose += strspn (&argvec[optind][1], "v");
}
else if (strcmp (argvec[optind], "-F") == 0)
{
msformat = strtol (argvec[++optind], NULL, 10);
}
else if (strcmp (argvec[optind], "-r") == 0)
{
reclen = strtol (argvec[++optind], NULL, 10);
}
else if (strcmp (argvec[optind], "-e") == 0)
{
encoding = strtol (argvec[++optind], NULL, 10);
}
else if (strcmp (argvec[optind], "-o") == 0)
{
outfile = argvec[++optind];
}
else
{
ms_log (2, "Unknown option: %s\n", argvec[optind]);
exit (1);
}
}
/* Make sure an outfile was specified */
if (!outfile)
{
ms_log (2, "No output file was specified\n\n");
ms_log (1, "Try %s -h for usage\n", PACKAGE);
exit (1);
}
if (msformat != 2 && msformat != 3)
{
ms_log (1, "Specified format must be 2 or 3, version %d is not supported\n", msformat);
exit (1);
}
/* Report the program version */
if (verbose)
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
return 0;
} /* End of parameter_proc() */
/***************************************************************************
* usage:
* Print the usage message and exit.
***************************************************************************/
static void
usage (void)
{
fprintf (stderr, "%s version: %s\n\n", PACKAGE, VERSION);
fprintf (stderr, "Usage: %s [options] -o outfile\n\n", PACKAGE);
fprintf (stderr,
" ## Options ##\n"
" -V Report program version\n"
" -h Show this usage message\n"
" -v Be more verbose, multiple flags can be used\n"
" -F format Specify miniSEED version format, default is v3\n"
" -r bytes Specify maximum record length in bytes, default 4096\n"
" -e encoding Specify encoding format\n"
"\n"
" -o outfile Specify the output file, required\n"
"\n"
"This program packs static, test data into miniSEED\n"
"\n");
} /* End of usage() */

@ -0,0 +1,147 @@
/***************************************************************************
* A program for illustrating the use of a Trace List as an
* intermediate, rolling buffer for production of data records.
*
* An input file of miniSEED is used as a convenient data source.
* MS3Records can be constructed for any arbitrary data and follow the
* same pattern of record generation.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
#include <libmseed.h>
/***************************************************************************
*
* A simple record handler callback function that parses and prints records
*
***************************************************************************/
void
record_handler (char *record, int reclen, void *handlerdata)
{
MS3Record *msr = NULL;
if (!msr3_parse (record, reclen, &msr, 0, 0))
{
msr3_print (msr, 0);
}
else
{
fprintf (stderr, "%s() Error parsing record\n", __func__);
}
msr3_free (&msr);
}
int
main (int argc, char **argv)
{
MS3Record *msr = NULL;
MS3TraceList *mstl = NULL;
char *inputfile = NULL;
uint32_t flags = 0;
int8_t verbose = 0;
int retcode;
int64_t psamples;
int precords;
int reclen = 256; /* Desired maximum record length */
uint8_t encoding = DE_STEIM2; /* Desired data encoding */
if (argc != 2)
{
ms_log (2, "Usage: %s <mseedfile>\n", argv[0]);
return 1;
}
inputfile = argv[1];
mstl = mstl3_init(NULL);
if (mstl == NULL)
{
ms_log (2, "Cannot allocate memory\n");
return 1;
}
/* Set bit flags to validate CRC and unpack data samples */
flags |= MSF_VALIDATECRC;
flags |= MSF_UNPACKDATA;
/* Loop over the input file as a source of data */
while ((retcode = ms3_readmsr (&msr, inputfile, flags, verbose)) == MS_NOERROR)
{
if (mstl3_addmsr (mstl, msr, 0, 1, flags, NULL) == NULL)
{
ms_log (2, "mstl2_addmsr() had problems\n");
break;
}
/* Attempt to pack data in the Trace List buffer.
* Only filled, or complete, records will be generated. */
ms_log (0, "Calling mstl3_pack() to generate records\n");
precords = mstl3_pack (mstl, // Pack data in this trace list
record_handler, // Callback function that will handle records
NULL, // Callback function data, none in this case
reclen, // Maximum record length
encoding, // Data encoding
&psamples, // Packed sample count
flags, // Flags to control packing
verbose, // Verbosity
NULL // Extra headers to inject, none in this case
);
ms_log (0, "mstl3_pack() created %d records containing %" PRId64 " samples\n",
precords, psamples);
}
if (retcode != MS_ENDOFFILE)
ms_log (2, "Error reading %s: %s\n", inputfile, ms_errorstr (retcode));
/* Final call to flush data buffers, adding MSF_FLUSHDATA flag */
ms_log (0, "Calling mstl3_pack() with MSF_FLUSHDATA flag\n");
precords = mstl3_pack (mstl, // Pack data in this trace list
record_handler, // Callback function that will handle records
NULL, // Callback function data, none in this case
reclen, // Maximum record length
encoding, // Data encoding
&psamples, // Packed sample count
(flags | MSF_FLUSHDATA), // Flags to control packing, adding flush flag
verbose, // Verbosity
NULL // Extra headers to inject, none in this case
);
ms_log (0, "Final mstl3_pack() created %d records containing %" PRId64 " samples\n",
precords, psamples);
/* Make sure everything is cleaned up */
ms3_readmsr (&msr, NULL, flags, 0);
if (msr)
msr3_free (&msr);
if (mstl)
mstl3_free (&mstl, 0);
return 0;
}

@ -0,0 +1,188 @@
/***************************************************************************
* A simple example of using libmseed to read miniSEED in parallel
* using re-entrant interfaces and POSIX threading.
*
* Windows is not supported.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <libmseed.h>
/* File read test portability, possibly in the future */
#if defined(LMP_WIN)
#define _access access
#define R_OK 4 /* Test for read permission */
#else
#include <pthread.h>
#include <unistd.h>
#endif
#define VERSION "[libmseed " LIBMSEED_VERSION " example]"
#define PACKAGE "lm_pararead"
static int8_t verbose = 0;
static int8_t printrecs = 0;
static uint32_t readflags = 0;
/* File information structure */
typedef struct FileEntry
{
char *filename;
pthread_t tid;
MS3TraceList *mstl;
uint64_t recordcount;
int result;
struct FileEntry *next;
} FileEntry;
/* List of files to read */
static FileEntry *files = NULL;
/* Thread function to read miniSEED file */
static void *ReadMSFileThread (void *vfe)
{
FileEntry *fe = (FileEntry *)vfe;
MS3FileParam *msfp = NULL;
MS3Record *msr = NULL;
/* NOTE: This example is contrived for illustration.
* The combination of ms3_readmsr_r() with mstl3_addmsr()
* is only needed if you wish to do something for each record.
* Otherwise, consider using ms3_readtracelist() if only
* a MS3TraceList is desired.*/
/* Loop over the input file record by record */
while ((fe->result = ms3_readmsr_r (&msfp, &msr,
fe->filename,
readflags, verbose)) == MS_NOERROR)
{
fe->recordcount++;
if (printrecs > 0)
msr3_print (msr, printrecs - 1);
/* Add record to trace list */
if (mstl3_addmsr (fe->mstl, msr, 0, 1, 0, NULL) == NULL)
{
ms_log (2, "Error adding record to list\n");
fe->result = 1;
}
}
/* Make sure everything is cleaned up */
ms3_readmsr_r (&msfp, &msr, NULL, 0, 0);
return NULL;
}
int
main (int argc, char **argv)
{
FileEntry *fe = NULL;
int idx;
/* Simplistic argument parsing */
for (idx = 1; idx < argc; idx++)
{
if (strncmp (argv[idx], "-v", 2) == 0)
verbose += strspn (&argv[idx][1], "v");
else if (strncmp (argv[idx], "-p", 2) == 0)
printrecs += strspn (&argv[idx][1], "p");
else
{
/* Add read-able files to file entry list */
if (access(argv[idx], R_OK) == 0)
{
if ((fe = (FileEntry *)malloc(sizeof(FileEntry))) == NULL)
{
ms_log (2, "Error allocating memory");
return -1;
}
fe->filename = argv[idx];
fe->mstl = mstl3_init(NULL);
fe->recordcount = 0;
fe->result = 0;
fe->next = files;
files = fe;
}
else
{
ms_log (2, "Cannot find file: %s\n", argv[idx]);
return -1;
}
}
}
/* Make sure input file(s) specified */
if (!files)
{
ms_log (1, "No input file(s) specified\n\n");
ms_log (1, "%s version %s\n\n", PACKAGE, VERSION);
ms_log (1, "Read specified miniSEED files in parallel\n\n");
ms_log (1, "Usage: %s [-p] [-v] file1 [file2 .. fileN]\n", PACKAGE);
ms_log (1, " -v Be more verbose, multiple flags can be used\n");
ms_log (1, " -p Print record details, multiple flags can be used\n\n");
return 0;
}
/* Report the program version */
if (verbose)
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
/* Add program name and version to User-Agent for URL-based requests */
if (libmseed_url_support() && ms3_url_useragent(PACKAGE, VERSION))
return -1;
/* Set flag to validate CRCs when reading */
readflags |= MSF_VALIDATECRC;
/* Parse byte range from file/URL path name if present */
readflags |= MSF_PNAMERANGE;
/* Create a thread to read each file */
for (fe = files; fe; fe = fe->next)
{
pthread_create (&(fe->tid), NULL, ReadMSFileThread, fe);
}
/* Wait for threads to finish */
for (fe = files; fe; fe = fe->next)
{
pthread_join(fe->tid, NULL);
}
/* Report details for each file */
for (fe = files; fe; fe = fe->next)
{
ms_log (0, "%s: records: %" PRIu64" result: %d\n",
fe->filename, fe->recordcount, fe->result);
if (fe->result == MS_NOERROR || fe->result == MS_ENDOFFILE)
mstl3_printtracelist (fe->mstl, ISOMONTHDAY, 1, 1, 0);
}
return 0;
} /* End of main() */

@ -0,0 +1,309 @@
/***************************************************************************
* A program for libmseed parsing tests.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <libmseed.h>
#define PACKAGE "lm_parse"
#define VERSION "[libmseed " LIBMSEED_VERSION " " PACKAGE " ]"
static flag verbose = 0;
static flag ppackets = 0;
static flag basicsum = 0;
static flag tracegap = 0;
static flag splitversion = 0;
static int printraw = 0;
static int printdata = 0;
static int reclen = -1;
static char *inputfile = NULL;
static int parameter_proc (int argcount, char **argvec);
static void usage (void);
/* Binary I/O for Windows platforms */
#ifdef LMP_WIN
#include <fcntl.h>
unsigned int _CRT_fmode = _O_BINARY;
#endif
int
main (int argc, char **argv)
{
MS3TraceList *mstl = 0;
MS3Record *msr = 0;
uint32_t flags = 0;
int64_t totalrecs = 0;
int64_t totalsamps = 0;
int retcode;
/* Process command line arguments */
if (parameter_proc (argc, argv) < 0)
return -1;
/* Validate CRC and unpack data samples */
flags |= MSF_VALIDATECRC;
/* Parse byte range from file/URL path name if present */
flags |= MSF_PNAMERANGE;
if (printdata)
flags |= MSF_UNPACKDATA;
if (tracegap)
mstl = mstl3_init (NULL);
/* Loop over the input file */
while ((retcode = ms3_readmsr (&msr, inputfile, flags, verbose)) == MS_NOERROR)
{
totalrecs++;
totalsamps += msr->samplecnt;
if (tracegap)
{
mstl3_addmsr (mstl, msr, splitversion, 1, flags, NULL);
}
else
{
if ( printraw )
{
if (msr->formatversion == 3)
ms_parse_raw3 (msr->record, msr->reclen, ppackets);
else
ms_parse_raw2 (msr->record, msr->reclen, ppackets, -1);
}
else
{
msr3_print (msr, ppackets);
}
if (printdata && msr->numsamples > 0)
{
int line, col, cnt, samplesize;
int lines = (msr->numsamples / 6) + 1;
void *sptr;
if ((samplesize = ms_samplesize (msr->sampletype)) == 0)
{
ms_log (2, "Unrecognized sample type: '%c'\n", msr->sampletype);
}
if (msr->sampletype == 't')
{
char *text = (char *)msr->datasamples;
int length = msr->numsamples;
ms_log (0, "Text data:\n");
/* Print maximum log message segments */
while (length > (MAX_LOG_MSG_LENGTH - 1))
{
ms_log (0, "%.*s", (MAX_LOG_MSG_LENGTH - 1), text);
text += MAX_LOG_MSG_LENGTH - 1;
length -= MAX_LOG_MSG_LENGTH - 1;
}
/* Print any remaining TEXT and add a newline */
if (length > 0)
{
ms_log (0, "%.*s\n", length, text);
}
else
{
ms_log (0, "\n");
}
}
else
for (cnt = 0, line = 0; line < lines; line++)
{
for (col = 0; col < 6; col++)
{
if (cnt < msr->numsamples)
{
sptr = (char *)msr->datasamples + (cnt * samplesize);
if (msr->sampletype == 'i')
ms_log (0, "%10d ", *(int32_t *)sptr);
else if (msr->sampletype == 'f')
ms_log (0, "%10.8g ", *(float *)sptr);
else if (msr->sampletype == 'd')
ms_log (0, "%10.10g ", *(double *)sptr);
cnt++;
}
}
ms_log (0, "\n");
/* If only printing the first 6 samples break out here */
if (printdata == 1)
break;
}
}
}
}
if (retcode != MS_ENDOFFILE)
ms_log (2, "Cannot read %s: %s\n", inputfile, ms_errorstr (retcode));
if (tracegap)
mstl3_printtracelist (mstl, ISOMONTHDAY_Z, 1, 1, splitversion);
/* Make sure everything is cleaned up */
ms3_readmsr (&msr, NULL, flags, 0);
if (mstl)
mstl3_free (&mstl, 0);
if (basicsum)
ms_log (1, "Records: %" PRId64 ", Samples: %" PRId64 "\n",
totalrecs, totalsamps);
return 0;
} /* End of main() */
/***************************************************************************
* parameter_proc():
* Process the command line arguments.
*
* Returns 0 on success, and -1 on failure
***************************************************************************/
static int
parameter_proc (int argcount, char **argvec)
{
int optind;
/* Process all command line arguments */
for (optind = 1; optind < argcount; optind++)
{
if (strcmp (argvec[optind], "-V") == 0)
{
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
exit (0);
}
else if (strcmp (argvec[optind], "-h") == 0)
{
usage ();
exit (0);
}
else if (strncmp (argvec[optind], "-v", 2) == 0)
{
verbose += strspn (&argvec[optind][1], "v");
}
else if (strncmp (argvec[optind], "-p", 2) == 0)
{
ppackets += strspn (&argvec[optind][1], "p");
}
else if (strncmp (argvec[optind], "-z", 2) == 0)
{
printraw = 1;
}
else if (strncmp (argvec[optind], "-d", 2) == 0)
{
printdata = 1;
}
else if (strncmp (argvec[optind], "-D", 2) == 0)
{
printdata = 2;
}
else if (strcmp (argvec[optind], "-P") == 0)
{
splitversion = 1;
}
else if (strncmp (argvec[optind], "-tg", 3) == 0)
{
tracegap = 1;
}
else if (strcmp (argvec[optind], "-s") == 0)
{
basicsum = 1;
}
else if (strcmp (argvec[optind], "-r") == 0)
{
reclen = atoi (argvec[++optind]);
}
else if (strncmp (argvec[optind], "-", 1) == 0 &&
strlen (argvec[optind]) > 1)
{
ms_log (2, "Unknown option: %s\n", argvec[optind]);
exit (1);
}
else if (inputfile == NULL)
{
inputfile = argvec[optind];
}
else
{
ms_log (2, "Unknown option: %s\n", argvec[optind]);
exit (1);
}
}
/* Make sure an inputfile was specified */
if (!inputfile)
{
ms_log (2, "No input file was specified\n\n");
ms_log (1, "%s version %s\n\n", PACKAGE, VERSION);
ms_log (1, "Try %s -h for usage\n", PACKAGE);
exit (1);
}
/* Add program name and version to User-Agent for URL-based requests */
if (libmseed_url_support() && ms3_url_useragent(PACKAGE, VERSION))
return -1;
/* Report the program version */
if (verbose)
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
return 0;
} /* End of parameter_proc() */
/***************************************************************************
* usage():
* Print the usage message and exit.
***************************************************************************/
static void
usage (void)
{
fprintf (stderr, "%s version: %s\n\n", PACKAGE, VERSION);
fprintf (stderr, "Usage: %s [options] file\n\n", PACKAGE);
fprintf (stderr,
" ## Options ##\n"
" -V Report program version\n"
" -h Show this usage message\n"
" -v Be more verbose, multiple flags can be used\n"
" -p Print details of header, multiple flags can be used\n"
" -z Print raw details of header\n"
" -d Print first 6 sample values\n"
" -D Print all sample values\n"
" -P Additionally group traces by data publication version\n"
" -tg Print trace listing with gap information\n"
" -s Print a basic summary after processing a file\n"
" -r bytes Specify record length in bytes, required if no Blockette 1000\n"
"\n"
" file File of miniSEED records\n"
"\n");
} /* End of usage() */

@ -0,0 +1,320 @@
/***************************************************************************
* A program illustrating reading miniSEED from buffers
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <errno.h>
#include <stdio.h>
#include <sys/stat.h>
#include <libmseed.h>
#define TESTCPPDLL_API __declspec(dllexport)
TESTCPPDLL_API int __stdcall MseedDatas (int argc, char **argv) // MseedDatas(char *argv, int length)
{
struct stat sb = {0};
int64_t records = 0;
FILE *fh;
MS3TraceList *mstl = NULL;
char *buffer = NULL;
uint64_t bufferlength = 0;
int8_t splitversion = 0;
uint32_t flags = 0;
int8_t verbose = 0;
if (argc != 2)
{
ms_log (2, "%s requires a single file name argument\n", argv[0]);
return -1;
}
/* Read specified file into buffer */
if (!(fh = fopen (argv[1], "rb")))
{
ms_log (2, "Error opening %s: %s\n", argv[1], strerror (errno));
return -1;
}
if (fstat (fileno (fh), &sb))
{
ms_log (2, "Error stating %s: %s\n", argv[1], strerror (errno));
return -1;
}
if (!(buffer = (char *)malloc (sb.st_size)))
{
ms_log (2, "Error allocating buffer of %" PRIsize_t " bytes\n",
(sb.st_size >= 0) ? (size_t)sb.st_size : 0);
return -1;
}
if (fread (buffer, sb.st_size, 1, fh) != 1)
{
ms_log (2, "Error reading file\n");
return -1;
}
fclose (fh);
bufferlength = sb.st_size;
/* Set bit flags to validate CRC and unpack data samples */
flags |= MSF_VALIDATECRC;
flags |= MSF_UNPACKDATA;
mstl = mstl3_init (NULL);
if (!mstl)
{
ms_log (2, "Error allocating MS3TraceList\n");
return -1;
}
/* Read all miniSEED in buffer, accumulate in MS3TraceList */
records = mstl3_readbuffer (&mstl, buffer, bufferlength,
splitversion, flags, NULL, verbose);
if (records < 0)
{
ms_log (2, "Problem reading miniSEED from buffer: %s\n", ms_errorstr (records));
}
/* Print summary */
mstl3_printtracelist (mstl, ISOMONTHDAY, 1, 1, 0);
ms_log (1, "Total records: %" PRId64 "\n", records);
/* Make sure everything is cleaned up */
if (mstl)
mstl3_free (&mstl, 0);
free (buffer);
return 0;
}
typedef struct AsciiDataStruct
{
char *sid;
char *starttime; //!< Time of first sample
char *endtime; //!< Time of last sample
double samprate; //!< Nominal sample rate (Hz)
int64_t samplecnt; //!< Number of samples in trace coverage
size_t datasize; //!< Size of datasamples buffer in bytes
int64_t numsamples; //!< Number of data samples in datasamples
char sampletype; //!< Sample type code, see @ref sample-types
uint8_t samplesize;
void *datasamples; //!< Data samples, \a numsamples of type \a sampletype
} AsciiDataStruct;
typedef void (__stdcall *generalDataFunction) (AsciiDataStruct AsciiData);
generalDataFunction generalData;
TESTCPPDLL_API void __stdcall MseedDatasCallFun (generalDataFunction fn)
{
generalData = fn;
}
TESTCPPDLL_API int __stdcall bufferMseedData (int argc, char *argv)
{
struct stat sb = {0};
int64_t records = 0;
FILE *fh;
MS3TraceList *mstl = NULL;
char *buffer = NULL;
uint64_t bufferlength = 0;
int8_t splitversion = 0;
uint32_t flags = 0;
int8_t verbose = 0;
// if (argc != 2)
//{
// ms_log (2, "%s requires a single file name argument\n", argv[0]);
// return -1;
// }
/* Read specified file into buffer
if (!(fh = fopen (argv[1], "rb")))
{
ms_log (2, "Error opening %s: %s\n", argv[1], strerror (errno));
return -1;
}
if (fstat (fileno (fh), &sb))
{
ms_log (2, "Error stating %s: %s\n", argv[1], strerror (errno));
return -1;
}
if (!(buffer = (char *)malloc (sb.st_size)))
{
ms_log (2, "Error allocating buffer of %" PRIsize_t " bytes\n",
(sb.st_size >= 0) ? (size_t)sb.st_size : 0);
return -1;
}
if (fread (buffer, sb.st_size, 1, fh) != 1)
{
ms_log (2, "Error reading file\n");
return -1;
}
fclose (fh);
*/
bufferlength = argc;
// buffer = argv;
/* Set bit flags to validate CRC and unpack data samples */
flags |= MSF_VALIDATECRC;
flags |= MSF_UNPACKDATA;
mstl = mstl3_init (NULL);
if (!mstl)
{
ms_log (2, "Error allocating MS3TraceList\n");
return -1;
}
/* Read all miniSEED in buffer, accumulate in MS3TraceList */
records = mstl3_readbuffer (&mstl, argv, bufferlength,
splitversion, flags, NULL, verbose);
if (records < 0)
{
ms_log (2, "Problem reading miniSEED from buffer: %s\n", ms_errorstr (records));
}
/* Print summary */
// mstl3_printtracelist (mstl, ISOMONTHDAY, 1, 1, 0);
/* Traverse trace list structures and print summary information */
MS3TraceID *tid = mstl->traces.next[0];
char starttimestr[30];
char endtimestr[30];
MS3TraceSeg *seg = NULL;
MS3RecordPtr *recptr = NULL;
char *mseedfile = NULL;
char bufferptrstr[30];
char fileptrstr[30];
size_t idx;
int rv;
char printdata = 'd';
int64_t unpacked;
uint8_t samplesize;
char sampletype;
size_t lineidx;
size_t lines;
int col;
void *sptr;
AsciiDataStruct ybbmqj;
/* Traverse trace list structures and print summary information */
tid = mstl->traces.next[0];
while (tid)
{
ms_log (0, "TraceID for %s (%d), segments: %u\n",
tid->sid, tid->pubversion, tid->numsegments);
seg = tid->first;
while (seg)
{
if (!ms_nstime2timestr (seg->starttime, starttimestr, ISOMONTHDAY, NANO) ||
!ms_nstime2timestr (seg->endtime, endtimestr, ISOMONTHDAY, NANO))
{
ms_log (2, "Cannot create time strings\n");
starttimestr[0] = endtimestr[0] = '\0';
}
ms_log (0, " Segment %s - %s, samples: %" PRId64 ", sample rate: %g\n",
starttimestr, endtimestr, seg->samplecnt, seg->samprate);
unpacked = seg->numsamples; // mstl3_unpack_recordlist (tid, seg, NULL, 0, verbose);
sampletype = seg->sampletype;
samplesize = ms_samplesize (seg->sampletype);
if (unpacked != seg->samplecnt)
{
ms_log (2, "Cannot unpack samples for %s\n", tid->sid);
}
else
{
ms_log (0, "DATA (%" PRId64 " samples) of type '%c':\n", seg->numsamples, seg->sampletype);
if (sampletype == 't')
{
printf ("%*s",
(seg->numsamples > INT_MAX) ? INT_MAX : (int)seg->numsamples,
(char *)seg->datasamples);
}
else
{
ybbmqj.sid = tid->sid;
ybbmqj.starttime = starttimestr;
ybbmqj.endtime = endtimestr;
ybbmqj.samprate = seg->samprate;
ybbmqj.samplecnt = seg->samplecnt;
ybbmqj.datasamples = seg->datasamples;
ybbmqj.numsamples = seg->numsamples;
ybbmqj.datasize = seg->datasize;
ybbmqj.samplesize = samplesize;
ybbmqj.sampletype = seg->sampletype;
if (generalData != NULL)
{
generalData (ybbmqj);
}
lines = (unpacked / 6) + 1;
//for (idx = 0, lineidx = 0; lineidx < lines; lineidx++)
//{
// for (col = 0; col < 6 && idx < seg->numsamples; col++)
// {
// sptr = (char *)seg->datasamples + (idx * samplesize);
// if (sampletype == 'i')
// ms_log (0, "%10d ", *(int32_t *)sptr);
// else if (sampletype == 'f')
// ms_log (0, "%10.8g ", *(float *)sptr);
// else if (sampletype == 'd')
// ms_log (0, "%10.10g ", *(double *)sptr);
// idx++;
// }
// ms_log (0, "\n");
// // if (printdata == 'd')
// // break;
//}
}
seg = seg->next;
}
}
tid = tid->next[0];
}
//****************************************************
ms_log (1, "Total records: %" PRId64 "\n", records);
/* Make sure everything is cleaned up */
if (mstl)
mstl3_free (&mstl, 0);
free (buffer);
return 0;
}

@ -0,0 +1,204 @@
/***************************************************************************
* A program for reading miniSEED into a trace list followed by
* unpacking from an associated record list.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <stdio.h>
#include <sys/stat.h>
#include <limits.h>
#include <errno.h>
#include <libmseed.h>
int
main (int argc, char **argv)
{
MS3TraceList *mstl = NULL;
MS3TraceID *tid = NULL;
MS3TraceSeg *seg = NULL;
MS3RecordPtr *recptr = NULL;
char *mseedfile = NULL;
char starttimestr[30];
char endtimestr[30];
char bufferptrstr[30];
char fileptrstr[30];
uint32_t flags = 0;
int8_t verbose = 0;
size_t idx;
int rv;
char printdata = 0;
int64_t unpacked;
uint8_t samplesize;
char sampletype;
size_t lineidx;
size_t lines;
int col;
void *sptr;
if (argc < 2)
{
ms_log (2, "Usage: %s <mseedfile> [-v] [-d] [-D]\n",argv[0]);
return -1;
}
mseedfile = argv[1];
/* Simplistic argument parsing */
for (idx = 2; idx < argc; idx++)
{
if (strncmp (argv[idx], "-v", 2) == 0)
verbose += strspn (&argv[idx][1], "v");
else if (strncmp (argv[idx], "-d", 2) == 0)
printdata = 'd';
else if (strncmp (argv[idx], "-D", 2) == 0)
printdata = 'D';
}
/* Set bit flag to validate CRC */
flags |= MSF_VALIDATECRC;
/* Set bit flag to build a record list */
flags |= MSF_RECORDLIST;
/* Read all miniSEED into a trace list, limiting to selections */
rv = ms3_readtracelist (&mstl, mseedfile, NULL, 0, flags, verbose);
if (rv != MS_NOERROR)
{
ms_log (2, "Cannot read miniSEED from file: %s\n", ms_errorstr(rv));
return -1;
}
/* Traverse trace list structures and print summary information */
tid = mstl->traces.next[0];
while (tid)
{
ms_log (0, "TraceID for %s (%d), segments: %u\n",
tid->sid, tid->pubversion, tid->numsegments);
seg = tid->first;
while (seg)
{
if (!ms_nstime2timestr (seg->starttime, starttimestr, ISOMONTHDAY, NANO) ||
!ms_nstime2timestr (seg->endtime, endtimestr, ISOMONTHDAY, NANO))
{
ms_log (2, "Cannot create time strings\n");
starttimestr[0] = endtimestr[0] = '\0';
}
ms_log (0, " Segment %s - %s, samples: %" PRId64 ", sample rate: %g\n",
starttimestr, endtimestr, seg->samplecnt, seg->samprate);
if (seg->recordlist)
{
ms_log (0, " Record list:\n");
/* Traverse record list print summary information */
recptr = seg->recordlist->first;
while (recptr)
{
if (recptr->bufferptr == NULL)
strcpy (bufferptrstr, "NULL");
else
snprintf (bufferptrstr, sizeof(bufferptrstr), "%" PRIu64, (uint64_t)recptr->bufferptr);
if (recptr->fileptr == NULL)
strcpy (fileptrstr, "NULL");
else
snprintf (fileptrstr, sizeof(fileptrstr), "%" PRIu64, (uint64_t)recptr->fileptr);
ms_log (0, " RECORD: bufferptr: %s, fileptr: %s, filename: %s, fileoffset: %"PRId64"\n",
bufferptrstr, fileptrstr, recptr->filename, recptr->fileoffset);
ms_nstime2timestr (recptr->msr->starttime, starttimestr, ISOMONTHDAY_Z, NANO);
ms_nstime2timestr (recptr->endtime, endtimestr, ISOMONTHDAY_Z, NANO);
ms_log (0, " Start: %s, End: %s\n", starttimestr, endtimestr);
recptr = recptr->next;
}
}
/* Unpack and print samples for this trace segment */
if (printdata && seg->recordlist && seg->recordlist->first)
{
/* Determine sample size and type based on encoding of first record */
ms_encoding_sizetype (seg->recordlist->first->msr->encoding, &samplesize, &sampletype);
/* Unpack data samples using record list.
* No data buffer is supplied, so it will be allocated and assigned to the segment.
* Alternatively, a user-specified data buffer can be provided here. */
unpacked = mstl3_unpack_recordlist (tid, seg, NULL, 0, verbose);
if (unpacked != seg->samplecnt)
{
ms_log (2, "Cannot unpack samples for %s\n", tid->sid);
}
else
{
ms_log (0, "DATA (%" PRId64 " samples) of type '%c':\n", seg->numsamples, seg->sampletype);
if (sampletype == 't')
{
printf ("%*s",
(seg->numsamples > INT_MAX) ? INT_MAX : (int)seg->numsamples,
(char *)seg->datasamples);
}
else
{
lines = (unpacked / 6) + 1;
for (idx = 0, lineidx = 0; lineidx < lines; lineidx++)
{
for (col = 0; col < 6 && idx < seg->numsamples; col++)
{
sptr = (char *)seg->datasamples + (idx * samplesize);
if (sampletype == 'i')
ms_log (0, "%10d ", *(int32_t *)sptr);
else if (sampletype == 'f')
ms_log (0, "%10.8g ", *(float *)sptr);
else if (sampletype == 'd')
ms_log (0, "%10.10g ", *(double *)sptr);
idx++;
}
ms_log (0, "\n");
if (printdata == 'd')
break;
}
}
}
}
seg = seg->next;
}
tid = tid->next[0];
}
/* Make sure everything is cleaned up */
if (mstl)
mstl3_free (&mstl, 0);
return 0;
}

@ -0,0 +1,117 @@
/***************************************************************************
* A program for reading miniSEED using data selections to limit which
* data is read. This program also illustrates traversing a trace
* list.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <stdio.h>
#include <sys/stat.h>
#include <errno.h>
#include <libmseed.h>
int
main (int argc, char **argv)
{
MS3Selections *selections = NULL;
MS3TraceList *mstl = NULL;
MS3TraceID *tid = NULL;
MS3TraceSeg *seg = NULL;
char *mseedfile = NULL;
char *selectionfile = NULL;
char starttimestr[30];
char endtimestr[30];
uint32_t flags = 0;
int8_t verbose = 0;
int rv;
if (argc != 3)
{
ms_log (2, "Usage: %s <mseedfile> <selectionfile>\n",argv[0]);
return -1;
}
mseedfile = argv[1];
selectionfile = argv[2];
/* Read data selections from specified file */
if (ms3_readselectionsfile (&selections, selectionfile) < 0)
{
ms_log (2, "Cannot read data selection file\n");
return -1;
}
/* Set bit flags to validate CRC and unpack data samples */
flags |= MSF_VALIDATECRC;
flags |= MSF_UNPACKDATA;
/* Read all miniSEED into a trace list, limiting to selections */
rv = ms3_readtracelist_selection (&mstl, mseedfile, NULL,
selections, 0, flags, verbose);
if (rv != MS_NOERROR)
{
ms_log (2, "Cannot read miniSEED from file: %s\n", ms_errorstr(rv));
return -1;
}
/* Traverse trace list structures and print summary information */
tid = mstl->traces.next[0];
while (tid)
{
if (!ms_nstime2timestr (tid->earliest, starttimestr, SEEDORDINAL, NANO_MICRO_NONE) ||
!ms_nstime2timestr (tid->latest, endtimestr, SEEDORDINAL, NANO_MICRO_NONE))
{
ms_log (2, "Cannot create time strings\n");
starttimestr[0] = endtimestr[0] = '\0';
}
ms_log (0, "TraceID for %s (%d), earliest: %s, latest: %s, segments: %u\n",
tid->sid, tid->pubversion, starttimestr, endtimestr, tid->numsegments);
seg = tid->first;
while (seg)
{
if (!ms_nstime2timestr (seg->starttime, starttimestr, SEEDORDINAL, NANO_MICRO_NONE) ||
!ms_nstime2timestr (seg->endtime, endtimestr, SEEDORDINAL, NANO_MICRO_NONE))
{
ms_log (2, "Cannot create time strings\n");
starttimestr[0] = endtimestr[0] = '\0';
}
ms_log (0, " Segment %s - %s, samples: %" PRId64 ", sample rate: %g, sample type: %c\n",
starttimestr, endtimestr, seg->numsamples, seg->samprate,
(seg->sampletype) ? seg->sampletype : ' ');
seg = seg->next;
}
tid = tid->next[0];
}
/* Make sure everything is cleaned up */
if (mstl)
mstl3_free (&mstl, 0);
if (selections)
ms3_freeselections (selections);
return 0;
}

@ -0,0 +1,87 @@
/***************************************************************************
* A program illustrating mapping source identifiers and SEED codes
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <libmseed.h>
int
map_sid (char *original_sid)
{
char sid[LM_SIDLEN];
char network[11];
char station[11];
char location[11];
char channel[31];
int rv;
/* Parse network, station, location and channel from SID */
rv = ms_sid2nslc (original_sid, network, station, location, channel);
if (rv)
{
printf ("Error returned ms_sid2nslc()\n");
return -1;
}
/* Construct SID from network, station, location and channel */
rv = ms_nslc2sid (sid, sizeof(sid), 0, network, station, location, channel);
if (rv <= 0)
{
printf ("Error returned ms_nslc2sid()\n");
return -1;
}
printf ("Original SID: '%s'\n", original_sid);
printf (" network: '%s', station: '%s', location: '%s', channel: '%s'\n",
network, station, location, channel);
printf (" SID: '%s'\n", sid);
return 0;
}
int
main (int argc, char **argv)
{
char *sid;
int idx;
sid = "FDSN:NET_STA_LOC_C_H_N";
if (map_sid (sid))
{
printf ("Error with map_sid()\n");
return 1;
}
/* Map each value give on the command line */
if (argc > 1)
{
for (idx = 1; idx < argc; idx++)
{
if (map_sid (argv[idx]))
{
printf ("Error with map_sid()\n");
return 1;
}
}
}
return 0;
}

@ -0,0 +1,118 @@
/***************************************************************************
* A program illustrating time string parsing and generation support.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <libmseed.h>
int
main (int argc, char **argv)
{
char *timestr;
char generated_timestr[40];
nstime_t nstime;
int idx;
if (argc < 2)
{
ms_log (0, "Usage: %s timestring1 [timestring2] [timestring3] [...]\n", argv[0]);
return 1;
}
for (idx = 1; idx < argc; idx++)
{
timestr = argv[idx];
printf ("Input time : %s\n", timestr);
/* Convert time string to epoch format */
nstime = ms_timestr2nstime (timestr);
if (nstime == NSTERROR)
{
ms_log (2, "Cannot convert time string to epoch format: '%s'\n", timestr);
return 1;
}
/* Convert epoch time to ISO month-day time string */
if (!ms_nstime2timestr (nstime, generated_timestr, ISOMONTHDAY, NANO_MICRO_NONE))
{
ms_log (2, "Cannot convert epoch to ISOMONTHDAY time string\n");
return 1;
}
printf ("ISOMONTH : %s\n", generated_timestr);
/* Convert epoch time to ISO month-day time string with Z designator */
if (!ms_nstime2timestr (nstime, generated_timestr, ISOMONTHDAY_Z, NANO_MICRO_NONE))
{
ms_log (2, "Cannot convert epoch to ISOMONTHDAY_Z time string\n");
return 1;
}
printf ("ISOMONTH_Z : %s\n", generated_timestr);
/* Convert epoch time to ISO month-day with day-of-year time string */
if (!ms_nstime2timestr (nstime, generated_timestr, ISOMONTHDAY_DOY, NANO_MICRO_NONE))
{
ms_log (2, "Cannot convert epoch to ISOMONTHDAY_DOY time string\n");
return 1;
}
printf ("ISOMONTH_DOY : %s\n", generated_timestr);
/* Convert epoch time to ISO month-day with day-of-year time string with Z designator */
if (!ms_nstime2timestr (nstime, generated_timestr, ISOMONTHDAY_DOY_Z, NANO_MICRO_NONE))
{
ms_log (2, "Cannot convert epoch to ISOMONTHDAY_DOY_Z time string\n");
return 1;
}
printf ("ISOMONTH_DOY_Z: %s\n", generated_timestr);
/* Convert epoch time to SEED-style ordinal (day-of-year) time string */
if (!ms_nstime2timestr (nstime, generated_timestr, SEEDORDINAL, NANO_MICRO_NONE))
{
ms_log (2, "Cannot convert epoch to SEEDORDINAL time string\n");
return 1;
}
printf ("SEEDORDINAL : %s\n", generated_timestr);
/* Convert epoch time to Unix epoch time string */
if (!ms_nstime2timestr (nstime, generated_timestr, UNIXEPOCH, NANO_MICRO_NONE))
{
ms_log (2, "Cannot convert epoch to UNIXEPOCH time string\n");
return 1;
}
printf ("UNIXEPOCH : %s\n", generated_timestr);
/* Convert epoch time to nanosecond epoch time string */
if (!ms_nstime2timestr (nstime, generated_timestr, NANOSECONDEPOCH, NANO_MICRO_NONE))
{
ms_log (2, "Cannot convert epoch to NANOSECONDEPOCH time string\n");
return 1;
}
printf ("NSEPOCH : %s\n", generated_timestr);
printf ("nstime_t : %" PRId64 "\n\n", nstime);
}
return 0;
}

@ -0,0 +1,235 @@
/***************************************************************************
* A simple example of using libmseed to read miniSEED.
*
* Opens a user specified file, parses the miniSEED records and prints
* details for each record.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <libmseed.h>
#define VERSION "[libmseed " LIBMSEED_VERSION " example]"
#define PACKAGE "mseedview"
static int8_t verbose = 0;
static int8_t ppackets = 0;
static int8_t basicsum = 0;
static int printdata = 0;
static char *inputfile = NULL;
static int parameter_proc (int argcount, char **argvec);
static void usage (void);
int
main (int argc, char **argv)
{
MS3Record *msr = NULL;
uint32_t flags = 0;
int64_t totalrecs = 0;
int64_t totalsamps = 0;
int retcode;
/* Process command line arguments */
if (parameter_proc (argc, argv) < 0)
return -1;
/* Set flag to validate CRCs when reading */
flags |= MSF_VALIDATECRC;
/* Parse byte range from file/URL path name if present */
flags |= MSF_PNAMERANGE;
/* Set flag to unpack data if printing samples */
if (printdata)
flags |= MSF_UNPACKDATA;
/* Enable accumulation of up to 10 error and warning messages */
ms_rloginit (NULL, NULL, NULL, NULL, 10);
/* Loop over the input file record by record */
while ((retcode = ms3_readmsr (&msr, inputfile, flags, verbose)) == MS_NOERROR)
{
totalrecs++;
totalsamps += msr->samplecnt;
msr3_print (msr, ppackets);
/* Print data samples */
if (printdata && msr->numsamples > 0)
{
int line, col, cnt, samplesize;
int lines = (msr->numsamples / 6) + 1;
void *sptr;
if ((samplesize = ms_samplesize (msr->sampletype)) == 0)
{
ms_log (2, "Unrecognized sample type: '%c'\n", msr->sampletype);
}
for (cnt = 0, line = 0; line < lines; line++)
{
for (col = 0; col < 6; col++)
{
if (cnt < msr->numsamples)
{
sptr = (char *)msr->datasamples + (cnt * samplesize);
if (msr->sampletype == 'i')
ms_log (0, "%10d ", *(int32_t *)sptr);
else if (msr->sampletype == 'f')
ms_log (0, "%10.8g ", *(float *)sptr);
else if (msr->sampletype == 'd')
ms_log (0, "%10.10g ", *(double *)sptr);
cnt++;
}
}
ms_log (0, "\n");
/* If only printing the first 6 samples break out here */
if (printdata == 1)
break;
}
}
}
/* Emit all accumulated warning and error messages */
ms_rlog_emit (NULL, 0, verbose);
/* Make sure everything is cleaned up */
ms3_readmsr (&msr, NULL, 0, 0);
if (basicsum)
ms_log (0, "Records: %" PRId64 ", Samples: %" PRId64 "\n",
totalrecs, totalsamps);
return 0;
} /* End of main() */
/***************************************************************************
* parameter_proc():
* Process the command line arguments.
*
* Returns 0 on success, and -1 on failure
***************************************************************************/
static int
parameter_proc (int argcount, char **argvec)
{
int optind;
/* Process all command line arguments */
for (optind = 1; optind < argcount; optind++)
{
if (strcmp (argvec[optind], "-V") == 0)
{
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
exit (0);
}
else if (strcmp (argvec[optind], "-h") == 0)
{
usage ();
exit (0);
}
else if (strncmp (argvec[optind], "-v", 2) == 0)
{
verbose += strspn (&argvec[optind][1], "v");
}
else if (strncmp (argvec[optind], "-p", 2) == 0)
{
ppackets += strspn (&argvec[optind][1], "p");
}
else if (strncmp (argvec[optind], "-d", 2) == 0)
{
printdata = 1;
}
else if (strncmp (argvec[optind], "-D", 2) == 0)
{
printdata = 2;
}
else if (strcmp (argvec[optind], "-s") == 0)
{
basicsum = 1;
}
else if (strncmp (argvec[optind], "-", 1) == 0 &&
strlen (argvec[optind]) > 1)
{
ms_log (2, "Unknown option: %s\n", argvec[optind]);
exit (1);
}
else if (inputfile == NULL)
{
inputfile = argvec[optind];
}
else
{
ms_log (2, "Unknown option: %s\n", argvec[optind]);
exit (1);
}
}
/* Make sure an input file was specified */
if (!inputfile)
{
ms_log (2, "No input file was specified\n\n");
ms_log (1, "%s version %s\n\n", PACKAGE, VERSION);
ms_log (1, "Try %s -h for usage\n", PACKAGE);
exit (1);
}
/* Add program name and version to User-Agent for URL-based requests */
if (libmseed_url_support() && ms3_url_useragent(PACKAGE, VERSION))
return -1;
/* Report the program version */
if (verbose)
ms_log (1, "%s version: %s\n", PACKAGE, VERSION);
return 0;
} /* End of parameter_proc() */
/***************************************************************************
* usage():
* Print the usage message and exit.
***************************************************************************/
static void
usage (void)
{
fprintf (stderr, "%s version: %s\n\n", PACKAGE, VERSION);
fprintf (stderr, "Usage: %s [options] file\n\n", PACKAGE);
fprintf (stderr,
" ## Options ##\n"
" -V Report program version\n"
" -h Show this usage message\n"
" -v Be more verbose, multiple flags can be used\n"
" -p Print details of header, multiple flags can be used\n"
" -d Print first 6 sample values\n"
" -D Print all sample values\n"
" -s Print a basic summary after processing a file\n"
"\n"
" file File of miniSEED records\n"
"\n");
} /* End of usage() */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,50 @@
/***************************************************************************
* Interface declarations for the extra header routines in extraheaders.c
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#ifndef EXTRAHEADERS_H
#define EXTRAHEADERS_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include "libmseed.h"
#include "yyjson.h"
/* Avoid unused parameter warnings in known cases */
#define UNUSED(x) (void)(x)
/* Private allocation wrappers for yyjson's allocator definition */
void *_priv_malloc(void *ctx, size_t size);
void *_priv_realloc(void *ctx, void *ptr, size_t oldsize, size_t size);
void _priv_free(void *ctx, void *ptr);
/* Internal structure for holding parsed JSON extra headers */
struct LM_PARSED_JSON_s
{
yyjson_doc *doc;
yyjson_mut_doc *mut_doc;
};
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -0,0 +1,185 @@
/***************************************************************************
* The contained ms_gmtime64_r() is a 64-bit version of the standard
* gmtime_r() and was derived from the y2038 project:
* https://github.com/evalEmpire/y2038/
*
* Original copyright and license are included.
***************************************************************************/
/*
Copyright (c) 2007-2010 Michael G Schwern
This software originally derived from Paul Sheer's pivotal_gmtime_r.c.
The MIT License:
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
*/
#include <stdlib.h>
#include <stdint.h>
#include <time.h>
static const char days_in_month[2][12] = {
{31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
{31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
};
static const short julian_days_by_month[2][12] = {
{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
{0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335},
};
static const short length_of_year[2] = {365, 366};
/* Some numbers relating to the gregorian cycle */
static const int64_t years_in_gregorian_cycle = 400;
#define days_in_gregorian_cycle ((365 * 400) + 100 - 4 + 1)
/* Let's assume people are going to be looking for dates in the future.
Let's provide some cheats so you can skip ahead.
This has a 4x speed boost when near 2008.
*/
/* Number of days since epoch on Jan 1st, 2008 GMT */
#define CHEAT_DAYS (1199145600 / 24 / 60 / 60)
#define CHEAT_YEARS 108
/* IS_LEAP is used all over the place to index on arrays, so make sure it always returns 0 or 1. */
#define IS_LEAP(n) ((!(((n) + 1900) % 400) || (!(((n) + 1900) % 4) && (((n) + 1900) % 100))) ? 1 : 0)
/* Allegedly, some <termios.h> define a macro called WRAP, so use a longer name like WRAP_TIME64. */
#define WRAP_TIME64(a, b, m) ((a) = ((a) < 0) ? ((b)--, (a) + (m)) : (a))
struct tm *
ms_gmtime64_r (const int64_t *in_time, struct tm *p)
{
int v_tm_sec, v_tm_min, v_tm_hour, v_tm_mon, v_tm_wday;
int64_t v_tm_tday;
int leap;
int64_t m;
int64_t time;
int64_t year = 70;
int64_t cycles = 0;
if (!in_time || !p)
return NULL;
time = *in_time;
v_tm_sec = (int)(time % 60);
time /= 60;
v_tm_min = (int)(time % 60);
time /= 60;
v_tm_hour = (int)(time % 24);
time /= 24;
v_tm_tday = time;
WRAP_TIME64 (v_tm_sec, v_tm_min, 60);
WRAP_TIME64 (v_tm_min, v_tm_hour, 60);
WRAP_TIME64 (v_tm_hour, v_tm_tday, 24);
v_tm_wday = (int)((v_tm_tday + 4) % 7);
if (v_tm_wday < 0)
v_tm_wday += 7;
m = v_tm_tday;
if (m >= CHEAT_DAYS)
{
year = CHEAT_YEARS;
m -= CHEAT_DAYS;
}
if (m >= 0)
{
/* Gregorian cycles, this is huge optimization for distant times */
cycles = m / (int64_t)days_in_gregorian_cycle;
if (cycles)
{
m -= cycles * (int64_t)days_in_gregorian_cycle;
year += cycles * years_in_gregorian_cycle;
}
/* Years */
leap = IS_LEAP (year);
while (m >= (int64_t)length_of_year[leap])
{
m -= (int64_t)length_of_year[leap];
year++;
leap = IS_LEAP (year);
}
/* Months */
v_tm_mon = 0;
while (m >= (int64_t)days_in_month[leap][v_tm_mon])
{
m -= (int64_t)days_in_month[leap][v_tm_mon];
v_tm_mon++;
}
}
else
{
year--;
/* Gregorian cycles */
cycles = (m / (int64_t)days_in_gregorian_cycle) + 1;
if (cycles)
{
m -= cycles * (int64_t)days_in_gregorian_cycle;
year += cycles * years_in_gregorian_cycle;
}
/* Years */
leap = IS_LEAP (year);
while (m < (int64_t)-length_of_year[leap])
{
m += (int64_t)length_of_year[leap];
year--;
leap = IS_LEAP (year);
}
/* Months */
v_tm_mon = 11;
while (m < (int64_t)-days_in_month[leap][v_tm_mon])
{
m += (int64_t)days_in_month[leap][v_tm_mon];
v_tm_mon--;
}
m += (int64_t)days_in_month[leap][v_tm_mon];
}
p->tm_year = (int)year;
if (p->tm_year != year)
{
return NULL;
}
/* At this point m is less than a year so casting to an int is safe */
p->tm_mday = (int)m + 1;
p->tm_yday = julian_days_by_month[leap][v_tm_mon] + (int)m;
p->tm_sec = v_tm_sec;
p->tm_min = v_tm_min;
p->tm_hour = v_tm_hour;
p->tm_mon = v_tm_mon;
p->tm_wday = v_tm_wday;
return p;
}

@ -0,0 +1,22 @@
/***************************************************************************
* Interface declaration for function in gmtime64.c.
*
* See gmtime.c for copyright and license.
***************************************************************************/
#ifndef GMTIME64_H
#define GMTIME64_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include "libmseed.h"
extern struct tm * ms_gmtime64_r (const int64_t *in_time, struct tm *p);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,100 @@
LIBRARY libmseed.dll
EXPORTS
ms_nstime2time
ms_nstime2timestr
ms_nstime2timestrz
ms_time2nstime
ms_timestr2nstime
ms_mdtimestr2nstime
ms_seedtimestr2nstime
ms_doy2md
ms_md2doy
msr3_parse
msr3_pack
msr3_repack_mseed3
msr3_pack_header3
msr3_pack_header2
msr3_unpack_data
msr3_data_bounds
ms_decode_data
msr3_init
msr3_free
msr3_duplicate
msr3_endtime
msr3_print
msr3_resize_buffer
msr3_sampratehz
msr3_host_latency
ms3_detect
ms_parse_raw3
ms_parse_raw2
ms3_matchselect
msr3_matchselect
ms3_addselect
ms3_addselect_comp
ms3_readselectionsfile
ms3_freeselections
ms3_printselections
mstl3_init
mstl3_free
mstl3_findID
mstl3_addmsr_recordptr
mstl3_readbuffer
mstl3_readbuffer_selection
mstl3_unpack_recordlist
mstl3_convertsamples
mstl3_resize_buffers
mstl3_pack
mstl3_printtracelist
mstl3_printsynclist
mstl3_printgaplist
ms3_readmsr
ms3_readmsr_r
ms3_readmsr_selection
ms3_readtracelist
ms3_readtracelist_timewin
ms3_readtracelist_selection
ms3_url_useragent
ms3_url_userpassword
ms3_url_addheader
ms3_url_freeheaders
msr3_writemseed
mstl3_writemseed
libmseed_url_support
ms_sid2nslc
ms_nslc2sid
ms_seedchan2xchan
ms_xchan2seedchan
ms_strncpclean
ms_strncpcleantail
ms_strncpopen
mseh_get_ptr_r
mseh_set_ptr_r
mseh_add_event_detection_r
mseh_add_calibration_r
mseh_add_timing_exception_r
mseh_add_recenter_r
mseh_serialize
mseh_free_parsestate
mseh_print
ms_rlog
ms_rlog_l
ms_rloginit
ms_rloginit_l
ms_rlog_emit
ms_rlog_free
ms_readleapseconds
ms_readleapsecondfile
ms_samplesize
ms_encoding_sizetype
ms_encodingstr
ms_errorstr
ms_sampletime
ms_dabs
ms_bigendianhost
ms_crc32c
ms_gswap2
ms_gswap4
ms_gswap8
leapsecondlist
libmseed_memory

File diff suppressed because it is too large Load Diff

Binary file not shown.

@ -0,0 +1,13 @@
{
global:
ms_*;
ms3_*;
msr_*;
msr3_*;
mstl3_*;
mseh_*;
leapsecondlist;
libmseed_memory;
local:
*;
};

@ -0,0 +1,657 @@
/***************************************************************************
* Common logging facility.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "libmseed.h"
void rloginit_int (MSLogParam *logp,
void (*log_print) (const char *), const char *logprefix,
void (*diag_print) (const char *), const char *errprefix,
int maxmessages);
int rlog_int (MSLogParam *logp, const char *function, int level,
const char *format, va_list *varlist);
int add_message_int (MSLogRegistry *logreg, const char *function, int level,
const char *message);
void print_message_int (MSLogParam *logp, int level, const char *message,
char *terminator);
/* Initialize the global logging parameters
*
* If not disabled by a defined LIBMSEED_NO_THREADING, use options for
* thread-local storage. In this default case each thread will have
* it's own "global" logging parameters initialized to the library
* default settings.
*
* Windows has its own designation for TLS.
* Otherwise, C11 defines the standardized _Thread_local storage-class.
* Otherwise fallback to the commonly supported __thread keyword.
*/
#if !defined(LIBMSEED_NO_THREADING)
#if defined(LMP_WIN)
#define lm_thread_local __declspec( thread )
#elif __STDC_VERSION__ >= 201112L
#define lm_thread_local _Thread_local
#else
#define lm_thread_local __thread
#endif
lm_thread_local MSLogParam gMSLogParam = MSLogParam_INITIALIZER;
#else
MSLogParam gMSLogParam = MSLogParam_INITIALIZER;
#endif
/**********************************************************************/ /**
* @brief Initialize the global logging parameters.
*
* Any message printing functions indicated must except a single
* argument, namely a string \c (const char *) that will contain the log
* message. If the function pointers are NULL, defaults will be used.
*
* If the log and error prefixes have been set they will be pre-pended
* to the message. If the prefixes are NULL, defaults will be used.
*
* If \a maxmessages is greater than zero, warning and error (level >=
* 1) messages will be accumulated in a message registry. Once the
* maximum number of messages have accumulated, the oldest messages
* are discarded. Messages in the registry can be printed using
* ms_rlog_emit() or cleared using ms_rlog_free().
*
* @param[in] log_print Function to print log messages
* @param[in] logprefix Prefix to add to log and diagnostic messages
* @param[in] diag_print Function to print diagnostic and error messages
* @param[in] errprefix Prefix to add to error messages
* @param[in] maxmessages Maximum number of error/warning messages to store in registry
*
* \sa ms_rlog()
* \sa ms_rlog_emit()
* \sa ms_rlog_free()
***************************************************************************/
void
ms_rloginit (void (*log_print) (const char *), const char *logprefix,
void (*diag_print) (const char *), const char *errprefix,
int maxmessages)
{
rloginit_int (&gMSLogParam, log_print, logprefix,
diag_print, errprefix, maxmessages);
} /* End of ms_rloginit() */
/**********************************************************************/ /**
* @brief Initialize specified ::MSLogParam logging parameters.
*
* If the logging parameters have not been initialized (logp == NULL),
* new parameter space will be allocated.
*
* Any message printing functions indicated must except a single
* argument, namely a string \c (const char *) that will contain the log
* message. If the function pointers are NULL, defaults will be used.
*
* If the log and error prefixes have been set they will be pre-pended
* to the message. If the prefixes are NULL, defaults will be used.
*
* If \a maxmessages is greater than zero, warning and error (level >=
* 1) messages will be accumulated in a message registry. Once the
* maximum number of messages have accumulated, the oldest messages
* are discarded. Messages in the registry can be printed using
* ms_rlog_emit() or cleared using ms_rlog_free().
*
* @param[in] logp ::MSLogParam logging parameters
* @param[in] log_print Function to print log messages
* @param[in] logprefix Prefix to add to log and diagnostic messages
* @param[in] diag_print Function to print diagnostic and error messages
* @param[in] errprefix Prefix to add to error messages
* @param[in] maxmessages Maximum number of error/warning messages to store in registry
*
* @returns a pointer to the created/re-initialized MSLogParam struct
* on success and NULL on error.
*
* \sa ms_rlog()
* \sa ms_rlog_emit()
* \sa ms_rlog_free()
***************************************************************************/
MSLogParam *
ms_rloginit_l (MSLogParam *logp,
void (*log_print) (const char *), const char *logprefix,
void (*diag_print) (const char *), const char *errprefix,
int maxmessages)
{
MSLogParam *llog;
if (logp == NULL)
{
llog = (MSLogParam *)libmseed_memory.malloc (sizeof (MSLogParam));
if (llog == NULL)
{
ms_log (2, "Cannot allocate memory");
return NULL;
}
llog->log_print = NULL;
llog->logprefix = NULL;
llog->diag_print = NULL;
llog->errprefix = NULL;
llog->registry.maxmessages = 0;
llog->registry.messagecnt = 0;
llog->registry.messages = NULL;
}
else
{
llog = logp;
}
rloginit_int (llog, log_print, logprefix,
diag_print, errprefix, maxmessages);
return llog;
} /* End of ms_rloginit_l() */
/**********************************************************************/ /**
* @brief Initialize the logging subsystem.
*
* This function modifies the logging parameters in the supplied
* ::MSLogParam. Use NULL for the function pointers or the prefixes if
* they should not be changed from previously set or default values.
*
***************************************************************************/
void
rloginit_int (MSLogParam *logp,
void (*log_print) (const char *), const char *logprefix,
void (*diag_print) (const char *), const char *errprefix,
int maxmessages)
{
if (!logp)
return;
if (log_print)
logp->log_print = log_print;
if (logprefix)
{
if (strlen (logprefix) >= MAX_LOG_MSG_LENGTH)
{
ms_log_l (logp, 2, "%s", "log message prefix is too large");
}
else
{
logp->logprefix = logprefix;
}
}
if (diag_print)
logp->diag_print = diag_print;
if (errprefix)
{
if (strlen (errprefix) >= MAX_LOG_MSG_LENGTH)
{
ms_log_l (logp, 2, "%s", "error message prefix is too large");
}
else
{
logp->errprefix = errprefix;
}
}
if (maxmessages >= 0)
{
logp->registry.maxmessages = maxmessages;
}
return;
} /* End of rloginit_int() */
/**********************************************************************/ /**
* @brief Register log message using global logging parameters.
*
* It is convenient to call this function via the ms_log() macro,
* which sets the calling function automatically.
*
* Three message levels are recognized, see @ref logging-levels for
* more information.
*
* This function builds the log/error message and passes to it to the
* appropriate print function. If custom printing functions have not
* been defined, messages will be printed with \c fprintf(), log
* messages to \c stdout and error messages to \c stderr.
*
* If the log/error prefixes have been set they will be pre-pended to
* the message. If no custom log prefix is set none will be included.
* If no custom error prefix is set \c "Error: " will be included.
*
* A trailing newline character is for error messages is removed if
* the message is added to the log registry.
*
* All messages will be truncated at the ::MAX_LOG_MSG_LENGTH, this
* includes any prefix.
*
* @param[in] function Name of function registering log message
* @param[in] level Message level
* @param[in] format Message format in printf() style
* @param[in] ... Message format variables
*
* @returns The number of characters formatted on success, and a
* negative value on error..
***************************************************************************/
int
ms_rlog (const char *function, int level, const char *format, ...)
{
int retval;
va_list varlist;
va_start (varlist, format);
retval = rlog_int (&gMSLogParam, function, level, format, &varlist);
va_end (varlist);
return retval;
} /* End of ms_rlog() */
/**********************************************************************/ /**
* @brief Register log message using specified logging parameters.
*
* It is convenient to call this function via the ms_log_l() macro,
* which sets the calling function automatically.
*
* The function uses logging parameters specified in the supplied
* ::MSLogParam. This reentrant capability allows using different
* parameters in different parts of a program or different threads.
*
* Three message levels are recognized, see @ref logging-levels for
* more information.
*
* This function builds the log/error message and passes to it to the
* appropriate print function. If custom printing functions have not
* been defined, messages will be printed with \c fprintf(), log
* messages to \c stdout and error messages to \c stderr.
*
* If the log/error prefixes have been set they will be pre-pended to
* the message. If no custom log prefix is set none will be included.
* If no custom error prefix is set \c "Error: " will be included.
*
* A trailing newline character is for error messages is removed if
* the message is added to the log registry.
*
* All messages will be truncated at the ::MAX_LOG_MSG_LENGTH, this
* includes any prefix.
*
* @param[in] logp Pointer to ::MSLogParam to use for this message
* @param[in] function Name of function registering log message
* @param[in] level Message level
* @param[in] format Message format in printf() style
* @param[in] ... Message format variables
*
* @returns The number of characters formatted on success, and a
* negative value on error.
***************************************************************************/
int
ms_rlog_l (MSLogParam *logp, const char *function, int level, const char *format, ...)
{
int retval;
va_list varlist;
if (!logp)
logp = &gMSLogParam;
va_start (varlist, format);
retval = rlog_int (logp, function, level, format, &varlist);
va_end (varlist);
return retval;
} /* End of ms_rlog_l() */
/**********************************************************************/ /**
* @brief Log message using specified logging parameters and \c va_list
*
* Trailing newline character is removed when added messages to the
* registry.
*
* @param[in] logp Pointer to ::MSLogParam to use for this message
* @param[in] function Name of function registering log message
* @param[in] level Message level
* @param[in] varlist Message in a \c va_list in printf() style
*
* @returns The number of characters formatted on success, and a
* negative value on error.
***************************************************************************/
int
rlog_int (MSLogParam *logp, const char *function, int level,
const char *format, va_list *varlist)
{
char message[MAX_LOG_MSG_LENGTH];
int presize = 0;
int printed = 0;
if (!logp)
{
fprintf (stderr, "%s() called without specifying log parameters", __func__);
return -1;
}
message[0] = '\0';
if (level >= 2) /* Error message */
{
if (logp->errprefix != NULL)
{
strncpy (message, logp->errprefix, MAX_LOG_MSG_LENGTH);
message[MAX_LOG_MSG_LENGTH - 1] = '\0';
}
else
{
strncpy (message, "Error: ", MAX_LOG_MSG_LENGTH);
}
presize = strlen (message);
printed = vsnprintf (&message[presize],
MAX_LOG_MSG_LENGTH - presize,
format, *varlist);
message[MAX_LOG_MSG_LENGTH - 1] = '\0';
}
else if (level == 1) /* Diagnostic message */
{
if (logp->logprefix != NULL)
{
strncpy (message, logp->logprefix, MAX_LOG_MSG_LENGTH);
message[MAX_LOG_MSG_LENGTH - 1] = '\0';
}
presize = strlen (message);
printed = vsnprintf (&message[presize],
MAX_LOG_MSG_LENGTH - presize,
format, *varlist);
message[MAX_LOG_MSG_LENGTH - 1] = '\0';
}
else if (level == 0) /* Normal log message */
{
if (logp->logprefix != NULL)
{
strncpy (message, logp->logprefix, MAX_LOG_MSG_LENGTH);
message[MAX_LOG_MSG_LENGTH - 1] = '\0';
}
presize = strlen (message);
printed = vsnprintf (&message[presize],
MAX_LOG_MSG_LENGTH - presize,
format, *varlist);
message[MAX_LOG_MSG_LENGTH - 1] = '\0';
}
printed += presize;
/* Add warning/error message to registry if enabled */
if (level >= 1 && logp->registry.maxmessages > 0)
{
/* Remove trailing newline if present */
if (message[printed - 1] == '\n')
{
message[printed - 1] = '\0';
printed -= 1;
}
add_message_int (&logp->registry, function, level, message);
}
else
{
print_message_int (logp, level, message, NULL);
}
return printed;
} /* End of rlog_int() */
/**********************************************************************/ /**
* @brief Add message to registry
*
* Add a message to the specified log registry. Earliest entries are
* removed to remain within the specified maximum number of messsages.
*
* @param[in] logreg Pointer to ::MSLogRegistry to use for this message
* @param[in] function Name of function generating the message
* @param[in] level Message level
* @param[in] message Message text
*
* @returns Zero on sucess and non-zero on error
***************************************************************************/
int
add_message_int (MSLogRegistry *logreg, const char *function, int level,
const char *message)
{
MSLogEntry *logentry = NULL;
MSLogEntry *lognext = NULL;
int count;
if (!logreg || !message)
return -1;
/* Allocate new entry */
logentry = (MSLogEntry *)libmseed_memory.malloc (sizeof (MSLogEntry));
if (logentry == NULL)
{
fprintf (stderr, "%s(): Cannot allocate memory for log message\n", __func__);
return -1;
}
/* Populate new entry */
logentry->level = level;
if (function)
{
strncpy (logentry->function, function, sizeof (logentry->function));
logentry->function[sizeof (logentry->function) - 1] = '\0';
}
else
{
logentry->function[0] = '\0';
}
strncpy (logentry->message, message, sizeof (logentry->message));
logentry->message[sizeof (logentry->message) - 1] = '\0';
/* Add entry to registry */
logentry->next = logreg->messages;
logreg->messages = logentry;
logreg->messagecnt += 1;
/* Remove earliest messages if more than maximum allowed */
if (logreg->messagecnt > logreg->maxmessages)
{
count = 0;
logentry = logreg->messages;
while (logentry)
{
lognext = logentry->next;
count++;
if (count == logreg->maxmessages)
logentry->next = NULL;
if (count > logreg->maxmessages)
free (logentry);
logentry = lognext;
}
}
return 0;
} /* End of add_message_int() */
/**********************************************************************/ /**
* @brief Send message to print functions
*
* @param[in] logp Pointer to ::MSLogParam appropriate for this message
* @param[in] level Message level
* @param[in] message Message to print
*
* @returns Zero on success, and a negative value on error.
***************************************************************************/
void
print_message_int (MSLogParam *logp, int level, const char *message,
char *terminator)
{
if (!logp || !message)
return;
if (level >= 1) /* Error or warning message */
{
if (logp->diag_print != NULL)
{
logp->diag_print (message);
}
else
{
fprintf (stderr, "%s%s", message, (terminator) ? terminator : "");
}
}
else if (level == 0) /* Normal log message */
{
if (logp->log_print != NULL)
{
logp->log_print (message);
}
else
{
fprintf (stdout, "%s%s", message, (terminator) ? terminator : "");
}
}
} /* End of print_message_int() */
/**********************************************************************/ /**
* @brief Emit, aka send to print functions, messages from log registry
*
* Emit messages from the log registry, using the printing functions
* identified by the ::MSLogParam.
*
* Messages are printed in order from earliest to latest.
*
* The maximum number messages to emit, from most recent to earliest,
* can be limited using \a count. If the value is 0 all messages are
* emitted. If this limit is used and messages are left in the
* registry, it is highly recommended to either emit them soon or
* clear them with ms_rlog_free(). A common pattern would be to emit
* the last message (e.g. \a count of 1) and immediately free
* (discard) any remaining messages.
*
* @param[in] logp ::MSLogParam for this message or NULL for global parameters
* @param[in] count Number of messages to emit, 0 to emit all messages
* @param[in] context If non-zero include context by prefixing the function name (if available)
*
* @returns The number of message emitted on success, and a negative
* value on error.
*
* \sa ms_rloginit()
* \sa ms_rlog_free()
***************************************************************************/
int
ms_rlog_emit (MSLogParam *logp, int count, int context)
{
MSLogEntry *logentry = NULL;
MSLogEntry *logprint = NULL;
char local_message[MAX_LOG_MSG_LENGTH];
char *message = NULL;
int emit = (count > 0) ? count : -1;
if (!logp)
logp = &gMSLogParam;
/* Pop off count entries (or all if count <= 0), and invert into print list */
logentry = logp->registry.messages;
while (logentry && emit)
{
logp->registry.messages = logentry->next;
logentry->next = logprint;
logprint = logentry;
if (emit > 0)
emit--;
logentry = logp->registry.messages;
}
/* Print and free entries */
logentry = logprint;
while (logprint)
{
/* Add function name to message if requested and present */
if (context && logprint->function[0] != '\0')
{
snprintf (local_message, sizeof(local_message), "%s() %.*s",
logprint->function,
(int)(MAX_LOG_MSG_LENGTH - sizeof(logprint->function) - 3),
logprint->message);
message = local_message;
}
else
{
message = logprint->message;
}
print_message_int (logp, logprint->level, message, "\n");
logentry = logprint->next;
free (logprint);
logprint = logentry;
}
return 0;
} /* End of ms_rlog_emit() */
/**********************************************************************/ /**
* @brief Free, without emitting, all messages from log registry
*
* @param[in] logp ::MSLogParam for this message or NULL for global parameters
*
* @returns The number of message freed on success, and a negative
* value on error.
***************************************************************************/
int
ms_rlog_free (MSLogParam *logp)
{
MSLogEntry *logentry = NULL;
int freed = 0;
if (!logp)
logp = &gMSLogParam;
logentry = logp->registry.messages;
while (logentry)
{
freed++;
logp->registry.messages = logentry->next;
free (logentry);
logentry = logp->registry.messages;
}
return freed;
} /* End of ms_rlog_free() */

@ -0,0 +1,239 @@
/***************************************************************************
* Generic lookup routines for miniSEED information.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <string.h>
#include "libmseed.h"
/**********************************************************************/ /**
* @brief Determine data sample size for each type
*
* @param[in] sampletype Library sample type code:
* @parblock
* - \c 't' - Text data type
* - \c 'i' - 32-bit integer data type
* - \c 'f' - 32-bit float data type
* - \c 'd' - 64-bit float (double) data type
* @endparblock
*
* @returns The sample size based on type code or 0 for unknown.
***************************************************************************/
uint8_t
ms_samplesize (char sampletype)
{
switch (sampletype)
{
case 't':
case 'a':
return 1;
break;
case 'i':
case 'f':
return 4;
break;
case 'd':
return 8;
break;
default:
return 0;
}
} /* End of ms_samplesize() */
/**********************************************************************/ /**
* @brief Return sample size and/or type for given encoding value
*
* Determine the decoded sample size and/or type based on data
* encoding. The \a samplesize and \a sampletype values will only be
* set if not NULL, allowing lookup of either value or both.
*
* @param[in] encoding Data sample encoding code
* @param[out] samplesize Size of sample, pointer that will be set
* @param[out] sampletype Sample type, pointer to \c char that will be set
*
* @returns 0 on success, -1 on error
***************************************************************************/
int
ms_encoding_sizetype (uint8_t encoding, uint8_t *samplesize, char *sampletype)
{
switch (encoding)
{
case DE_TEXT:
if (samplesize)
*samplesize = 1;
if (sampletype)
*sampletype = 't';
break;
case DE_INT16:
case DE_INT32:
case DE_STEIM1:
case DE_STEIM2:
case DE_CDSN:
case DE_SRO:
case DE_DWWSSN:
if (samplesize)
*samplesize = 4;
if (sampletype)
*sampletype = 'i';
break;
case DE_FLOAT32:
case DE_GEOSCOPE24:
case DE_GEOSCOPE163:
case DE_GEOSCOPE164:
if (samplesize)
*samplesize = 4;
if (sampletype)
*sampletype = 'f';
break;
case DE_FLOAT64:
if (samplesize)
*samplesize = 8;
if (sampletype)
*sampletype = 'd';
break;
default:
return -1;
}
return 0;
} /* End of ms_encodingstr_sizetype() */
/**********************************************************************/ /**
* @brief Descriptive string for data encodings
*
* @param[in] encoding Data sample encoding code
*
* @returns a string describing a data encoding format
***************************************************************************/
const char *
ms_encodingstr (uint8_t encoding)
{
switch (encoding)
{
case 0:
return "Text";
break;
case 1:
return "16-bit integer";
break;
case 2:
return "24-bit integer";
break;
case 3:
return "32-bit integer";
break;
case 4:
return "32-bit float (IEEE single)";
break;
case 5:
return "64-bit float (IEEE double)";
break;
case 10:
return "STEIM-1 integer compression";
break;
case 11:
return "STEIM-2 integer compression";
break;
case 12:
return "GEOSCOPE Muxed 24-bit integer";
break;
case 13:
return "GEOSCOPE Muxed 16/3-bit gain/exp";
break;
case 14:
return "GEOSCOPE Muxed 16/4-bit gain/exp";
break;
case 15:
return "US National Network compression";
break;
case 16:
return "CDSN 16-bit gain ranged";
break;
case 17:
return "Graefenberg 16-bit gain ranged";
break;
case 18:
return "IPG - Strasbourg 16-bit gain";
break;
case 19:
return "STEIM-3 integer compression";
break;
case 30:
return "SRO gain ranged";
break;
case 31:
return "HGLP";
break;
case 32:
return "DWWSSN";
break;
case 33:
return "RSTN 16 bit gain ranged";
break;
default:
return "Unknown";
}
} /* End of ms_encodingstr() */
/**********************************************************************/ /**
* @brief Descriptive string for library @ref return-values
*
* @param[in] errorcode Library error code
*
* @returns a string describing the library error code or NULL if the
* code is unknown.
***************************************************************************/
const char *
ms_errorstr (int errorcode)
{
switch (errorcode)
{
case MS_ENDOFFILE:
return "End of file reached";
break;
case MS_NOERROR:
return "No error";
break;
case MS_GENERROR:
return "Generic error";
break;
case MS_NOTSEED:
return "No miniSEED data detected";
break;
case MS_WRONGLENGTH:
return "Length of data read does not match record length";
break;
case MS_OUTOFRANGE:
return "SEED record length out of range";
break;
case MS_UNKNOWNFORMAT:
return "Unknown data encoding format";
break;
case MS_STBADCOMPFLAG:
return "Bad Steim compression flag(s) detected";
break;
case MS_INVALIDCRC:
return "Invalid CRC detected";
break;
}
return NULL;
} /* End of ms_errorstr() */

@ -0,0 +1,11 @@
prefix=@PREFIX@
exec_prefix=@EXEC_PREFIX@
libdir=@LIBDIR@
includedir=@INCLUDEDIR@
Name: libmseed
Description: Read and write miniSEED data records (seismological format)
URL: https://earthscope.github.io/libmseed/
Version: @VERSION@
Cflags: -I${includedir}
Libs: -L${libdir} -lmseed

@ -0,0 +1,658 @@
/***************************************************************************
* Documentation and helpers for miniSEED structures.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#ifndef MSEEDFORMAT_H
#define MSEEDFORMAT_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
#include "libmseed.h"
/* Length of Fixed Section of Data Header for miniSEED 3 */
#define MS3FSDH_LENGTH 40
/***************************************************************************
* miniSEED 3.0 Fixed Section of Data Header
* 40 bytes, plus length of identifier, plus length of extra headers
*
* # FIELD TYPE OFFSET
* 1 record indicator char[2] 0
* 2 format version uint8_t 2
* 3 flags uint8_t 3
* 4a nanosecond uint32_t 4
* 4b year uint16_t 8
* 4c day uint16_t 10
* 4d hour uint8_t 12
* 4e min uint8_t 13
* 4f sec uint8_t 14
* 5 data encoding uint8_t 15
* 6 sample rate/period float64 16
* 7 number of samples uint32_t 24
* 8 CRC of record uint32_t 28
* 9 publication version uint8_t 32
* 10 length of identifer uint8_t 33
* 11 length of extra headers uint16_t 34
* 12 length of data payload uint32_t 36
* 13 source identifier char 40
* 14 extra headers char 40 + field 10
* 15 data payload encoded 40 + field 10 + field 11
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS3FSDH_INDICATOR(record) ((char*)record)
#define pMS3FSDH_FORMATVERSION(record) ((uint8_t*)((uint8_t*)record+2))
#define pMS3FSDH_FLAGS(record) ((uint8_t*)((uint8_t*)record+3))
#define pMS3FSDH_NSEC(record) ((uint32_t*)((uint8_t*)record+4))
#define pMS3FSDH_YEAR(record) ((uint16_t*)((uint8_t*)record+8))
#define pMS3FSDH_DAY(record) ((uint16_t*)((uint8_t*)record+10))
#define pMS3FSDH_HOUR(record) ((uint8_t*)((uint8_t*)record+12))
#define pMS3FSDH_MIN(record) ((uint8_t*)((uint8_t*)record+13))
#define pMS3FSDH_SEC(record) ((uint8_t*)((uint8_t*)record+14))
#define pMS3FSDH_ENCODING(record) ((uint8_t*)((uint8_t*)record+15))
#define pMS3FSDH_SAMPLERATE(record) ((double*)((uint8_t*)record+16))
#define pMS3FSDH_NUMSAMPLES(record) ((uint32_t*)((uint8_t*)record+24))
#define pMS3FSDH_CRC(record) ((uint32_t*)((uint8_t*)record+28))
#define pMS3FSDH_PUBVERSION(record) ((uint8_t*)((uint8_t*)record+32))
#define pMS3FSDH_SIDLENGTH(record) ((uint8_t*)((uint8_t*)record+33))
#define pMS3FSDH_EXTRALENGTH(record) ((uint16_t*)((uint8_t*)record+34))
#define pMS3FSDH_DATALENGTH(record) ((uint32_t*)((uint8_t*)record+36))
#define pMS3FSDH_SID(record) ((char*)((uint8_t*)record+40))
/***************************************************************************
* miniSEED 2.4 Fixed Section of Data Header
* 48 bytes total
*
* FIELD TYPE OFFSET
* sequence_number char[6] 0
* dataquality char 6
* reserved char 7
* station char[5] 8
* location char[2] 13
* channel char[3] 15
* network char[2] 18
* year uint16_t 20
* day uint16_t 22
* hour uint8_t 24
* min uint8_t 25
* sec uint8_t 26
* unused uint8_t 27
* fract uint16_t 28
* numsamples uint16_t 30
* samprate_fact int16_t 32
* samprate_mult int16_t 34
* act_flags uint8_t 36
* io_flags uint8_t 37
* dq_flags uint8_t 38
* numblockettes uint8_t 39
* time_correct int32_t 40
* data_offset uint16_t 44
* blockette_offset uint16_t 46
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2FSDH_SEQNUM(record) ((char*)record)
#define pMS2FSDH_DATAQUALITY(record) ((char*)((uint8_t*)record+6))
#define pMS2FSDH_RESERVED(record) ((char*)((uint8_t*)record+7))
#define pMS2FSDH_STATION(record) ((char*)((uint8_t*)record+8))
#define pMS2FSDH_LOCATION(record) ((char*)((uint8_t*)record+13))
#define pMS2FSDH_CHANNEL(record) ((char*)((uint8_t*)record+15))
#define pMS2FSDH_NETWORK(record) ((char*)((uint8_t*)record+18))
#define pMS2FSDH_YEAR(record) ((uint16_t*)((uint8_t*)record+20))
#define pMS2FSDH_DAY(record) ((uint16_t*)((uint8_t*)record+22))
#define pMS2FSDH_HOUR(record) ((uint8_t*)((uint8_t*)record+24))
#define pMS2FSDH_MIN(record) ((uint8_t*)((uint8_t*)record+25))
#define pMS2FSDH_SEC(record) ((uint8_t*)((uint8_t*)record+26))
#define pMS2FSDH_UNUSED(record) ((uint8_t*)((uint8_t*)record+27))
#define pMS2FSDH_FSEC(record) ((uint16_t*)((uint8_t*)record+28))
#define pMS2FSDH_NUMSAMPLES(record) ((uint16_t*)((uint8_t*)record+30))
#define pMS2FSDH_SAMPLERATEFACT(record) ((int16_t*)((uint8_t*)record+32))
#define pMS2FSDH_SAMPLERATEMULT(record) ((int16_t*)((uint8_t*)record+34))
#define pMS2FSDH_ACTFLAGS(record) ((uint8_t*)((uint8_t*)record+36))
#define pMS2FSDH_IOFLAGS(record) ((uint8_t*)((uint8_t*)record+37))
#define pMS2FSDH_DQFLAGS(record) ((uint8_t*)((uint8_t*)record+38))
#define pMS2FSDH_NUMBLOCKETTES(record) ((uint8_t*)((uint8_t*)record+39))
#define pMS2FSDH_TIMECORRECT(record) ((int32_t*)((uint8_t*)record+40))
#define pMS2FSDH_DATAOFFSET(record) ((uint16_t*)((uint8_t*)record+44))
#define pMS2FSDH_BLOCKETTEOFFSET(record) ((uint16_t*)((uint8_t*)record+46))
/***************************************************************************
* miniSEED 2.4 Blockette 100 - sample rate
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* samprate float 4
* flags uint8_t 8
* reserved uint8_t[3] 9
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B100_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B100_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B100_SAMPRATE(blockette) ((float*)((uint8_t*)blockette+4))
#define pMS2B100_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+8))
#define pMS2B100_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+9))
/***************************************************************************
* miniSEED 2.4 Blockette 200 - generic event detection
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* amplitude float 4
* period float 8
* background_est float 12
* flags uint8_t 16
* reserved uint8_t 17
* year uint16_t 18
* day uint16_t 20
* hour uint8_t 22
* min uint8_t 23
* sec uint8_t 24
* unused uint8_t 25
* fract uint16_t 26
* detector char[24] 28
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B200_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B200_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B200_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+4))
#define pMS2B200_PERIOD(blockette) ((float*)((uint8_t*)blockette+8))
#define pMS2B200_BACKGROUNDEST(blockette) ((float*)((uint8_t*)blockette+12))
#define pMS2B200_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+16))
#define pMS2B200_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+17))
#define pMS2B200_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+18))
#define pMS2B200_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+20))
#define pMS2B200_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+22))
#define pMS2B200_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+23))
#define pMS2B200_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+24))
#define pMS2B200_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+25))
#define pMS2B200_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+26))
#define pMS2B200_DETECTOR(blockette) ((char*)((uint8_t*)blockette+28))
/***************************************************************************
* miniSEED 2.4 Blockette 201 - Murdock event detection
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* amplitude float 4
* period float 8
* background_est float 12
* flags uint8_t 16
* reserved uint8_t 17
* year uint16_t 18
* day uint16_t 20
* hour uint8_t 22
* min uint8_t 23
* sec uint8_t 24
* unused uint8_t 25
* fract uint16_t 26
* snr_values uint8_t[6] 28
* loopback uint8_t 34
* pick_algorithm uint8_t 35
* detector char[24] 36
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B201_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B201_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B201_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+4))
#define pMS2B201_PERIOD(blockette) ((float*)((uint8_t*)blockette+8))
#define pMS2B201_BACKGROUNDEST(blockette) ((float*)((uint8_t*)blockette+12))
#define pMS2B201_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+16))
#define pMS2B201_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+17))
#define pMS2B201_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+18))
#define pMS2B201_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+20))
#define pMS2B201_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+22))
#define pMS2B201_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+23))
#define pMS2B201_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+24))
#define pMS2B201_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+25))
#define pMS2B201_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+26))
#define pMS2B201_MEDSNR(blockette) ((uint8_t*)((uint8_t*)blockette+28))
#define pMS2B201_LOOPBACK(blockette) ((uint8_t*)((uint8_t*)blockette+34))
#define pMS2B201_PICKALGORITHM(blockette) ((uint8_t*)((uint8_t*)blockette+35))
#define pMS2B201_DETECTOR(blockette) ((char*)((uint8_t*)blockette+36))
/***************************************************************************
* miniSEED 2.4 Blockette 300 - step calibration
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* year uint16_t 4
* day uint16_t 6
* hour uint8_t 8
* min uint8_t 9
* sec uint8_t 10
* unused uint8_t 11
* fract uint16_t 12
* num calibrations uint8_t 14
* flags uint8_t 15
* step duration uint32_t 16
* interval duration uint32_t 20
* amplitude float 24
* input channel char[3] 28
* reserved uint8_t 31
* reference amplitude uint32_t 32
* coupling char[12] 36
* rolloff char[12] 48
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B300_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B300_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B300_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
#define pMS2B300_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
#define pMS2B300_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
#define pMS2B300_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
#define pMS2B300_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
#define pMS2B300_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
#define pMS2B300_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
#define pMS2B300_NUMCALIBRATIONS(blockette) ((uint8_t*)((uint8_t*)blockette+14))
#define pMS2B300_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+15))
#define pMS2B300_STEPDURATION(blockette) ((uint32_t*)((uint8_t*)blockette+16))
#define pMS2B300_INTERVALDURATION(blockette) ((uint32_t*)((uint8_t*)blockette+20))
#define pMS2B300_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+24))
#define pMS2B300_INPUTCHANNEL(blockette) ((char *)((uint8_t*)blockette+28))
#define pMS2B300_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+31))
#define pMS2B300_REFERENCEAMPLITUDE(blockette) ((uint32_t*)((uint8_t*)blockette+32))
#define pMS2B300_COUPLING(blockette) ((char*)((uint8_t*)blockette+36))
#define pMS2B300_ROLLOFF(blockette) ((char*)((uint8_t*)blockette+48))
/***************************************************************************
* miniSEED 2.4 Blockette 310 - sine calibration
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* year uint16_t 4
* day uint16_t 6
* hour uint8_t 8
* min uint8_t 9
* sec uint8_t 10
* unused uint8_t 11
* fract uint16_t 12
* reserved1 uint8_t 14
* flags uint8_t 15
* duration uint32_t 16
* period float 20
* amplitude float 24
* input channel char[3] 28
* reserved2 uint8_t 31
* reference amplitude uint32_t 32
* coupling char[12] 36
* rolloff char[12] 48
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B310_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B310_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B310_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
#define pMS2B310_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
#define pMS2B310_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
#define pMS2B310_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
#define pMS2B310_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
#define pMS2B310_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
#define pMS2B310_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
#define pMS2B310_RESERVED1(blockette) ((uint8_t*)((uint8_t*)blockette+14))
#define pMS2B310_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+15))
#define pMS2B310_DURATION(blockette) ((uint32_t*)((uint8_t*)blockette+16))
#define pMS2B310_PERIOD(blockette) ((float*)((uint8_t*)blockette+20))
#define pMS2B310_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+24))
#define pMS2B310_INPUTCHANNEL(blockette) ((char *)((uint8_t*)blockette+28))
#define pMS2B310_RESERVED2(blockette) ((uint8_t*)((uint8_t*)blockette+31))
#define pMS2B310_REFERENCEAMPLITUDE(blockette) ((uint32_t*)((uint8_t*)blockette+32))
#define pMS2B310_COUPLING(blockette) ((char*)((uint8_t*)blockette+36))
#define pMS2B310_ROLLOFF(blockette) ((char*)((uint8_t*)blockette+48))
/***************************************************************************
* miniSEED 2.4 Blockette 320 - pseudo-random calibration
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* year uint16_t 4
* day uint16_t 6
* hour uint8_t 8
* min uint8_t 9
* sec uint8_t 10
* unused uint8_t 11
* fract uint16_t 12
* reserved1 uint8_t 14
* flags uint8_t 15
* duration uint32_t 16
* PtP amplitude float 20
* input channel char[3] 24
* reserved2 uint8_t 27
* reference amplitude uint32_t 28
* coupling char[12] 32
* rolloff char[12] 44
* noise type char[8] 56
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B320_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B320_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B320_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
#define pMS2B320_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
#define pMS2B320_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
#define pMS2B320_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
#define pMS2B320_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
#define pMS2B320_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
#define pMS2B320_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
#define pMS2B320_RESERVED1(blockette) ((uint8_t*)((uint8_t*)blockette+14))
#define pMS2B320_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+15))
#define pMS2B320_DURATION(blockette) ((uint32_t*)((uint8_t*)blockette+16))
#define pMS2B320_PTPAMPLITUDE(blockette) ((float*)((uint8_t*)blockette+20))
#define pMS2B320_INPUTCHANNEL(blockette) ((char *)((uint8_t*)blockette+24))
#define pMS2B320_RESERVED2(blockette) ((uint8_t*)((uint8_t*)blockette+27))
#define pMS2B320_REFERENCEAMPLITUDE(blockette) ((uint32_t*)((uint8_t*)blockette+28))
#define pMS2B320_COUPLING(blockette) ((char*)((uint8_t*)blockette+32))
#define pMS2B320_ROLLOFF(blockette) ((char*)((uint8_t*)blockette+44))
#define pMS2B320_NOISETYPE(blockette) ((char*)((uint8_t*)blockette+56))
/***************************************************************************
* miniSEED 2.4 Blockette 390 - generic calibration
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* year uint16_t 4
* day uint16_t 6
* hour uint8_t 8
* min uint8_t 9
* sec uint8_t 10
* unused uint8_t 11
* fract uint16_t 12
* reserved1 uint8_t 14
* flags uint8_t 15
* duration uint32_t 16
* amplitude float 20
* input channel char[3] 24
* reserved2 uint8_t 27
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B390_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B390_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B390_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
#define pMS2B390_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
#define pMS2B390_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
#define pMS2B390_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
#define pMS2B390_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
#define pMS2B390_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
#define pMS2B390_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
#define pMS2B390_RESERVED1(blockette) ((uint8_t*)((uint8_t*)blockette+14))
#define pMS2B390_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+15))
#define pMS2B390_DURATION(blockette) ((uint32_t*)((uint8_t*)blockette+16))
#define pMS2B390_AMPLITUDE(blockette) ((float*)((uint8_t*)blockette+20))
#define pMS2B390_INPUTCHANNEL(blockette) ((char *)((uint8_t*)blockette+24))
#define pMS2B390_RESERVED2(blockette) ((uint8_t*)((uint8_t*)blockette+27))
/***************************************************************************
* miniSEED 2.4 Blockette 395 - calibration abort
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* year uint16_t 4
* day uint16_t 6
* hour uint8_t 8
* min uint8_t 9
* sec uint8_t 10
* unused uint8_t 11
* fract uint16_t 12
* reserved uint8_t[2] 14
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B395_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B395_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B395_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+4))
#define pMS2B395_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+6))
#define pMS2B395_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+8))
#define pMS2B395_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+9))
#define pMS2B395_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+10))
#define pMS2B395_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+11))
#define pMS2B395_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+12))
#define pMS2B395_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+14))
/***************************************************************************
* miniSEED 2.4 Blockette 400 - beam
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* azimuth float 4
* slowness float 8
* configuration uint16_t 12
* reserved uint8_t[2] 14
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B400_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B400_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B400_AZIMUTH(blockette) ((float*)((uint8_t*)blockette+4))
#define pMS2B400_SLOWNESS(blockette) ((float*)((uint8_t*)blockette+8))
#define pMS2B400_CONFIGURATION(blockette) ((uint16_t*)((uint8_t*)blockette+12))
#define pMS2B400_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+14))
/***************************************************************************
* miniSEED 2.4 Blockette 405 - beam delay
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* delay values uint16_t[1] 4
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B405_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B405_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B405_DELAYVALUES(blockette) ((uint16_t*)((uint8_t*)blockette+4))
/***************************************************************************
* miniSEED 2.4 Blockette 500 - timing
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* VCO correction float 4
* year uint16_t 8
* day uint16_t 10
* hour uint8_t 12
* min uint8_t 13
* sec uint8_t 14
* unused uint8_t 15
* fract uint16_t 16
* microsecond int8_t 18
* reception quality uint8_t 19
* exception count uint32_t 20
* exception type char[16] 24
* clock model char[32] 40
* clock status char[128] 72
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B500_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B500_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B500_VCOCORRECTION(blockette) ((float*)((uint8_t*)blockette+4))
#define pMS2B500_YEAR(blockette) ((uint16_t*)((uint8_t*)blockette+8))
#define pMS2B500_DAY(blockette) ((uint16_t*)((uint8_t*)blockette+10))
#define pMS2B500_HOUR(blockette) ((uint8_t*)((uint8_t*)blockette+12))
#define pMS2B500_MIN(blockette) ((uint8_t*)((uint8_t*)blockette+13))
#define pMS2B500_SEC(blockette) ((uint8_t*)((uint8_t*)blockette+14))
#define pMS2B500_UNUSED(blockette) ((uint8_t*)((uint8_t*)blockette+15))
#define pMS2B500_FSEC(blockette) ((uint16_t*)((uint8_t*)blockette+16))
#define pMS2B500_MICROSECOND(blockette) ((int8_t*)((uint8_t*)blockette+18))
#define pMS2B500_RECEPTIONQUALITY(blockette) ((uint8_t*)((uint8_t*)blockette+19))
#define pMS2B500_EXCEPTIONCOUNT(blockette) ((uint32_t*)((uint8_t*)blockette+20))
#define pMS2B500_EXCEPTIONTYPE(blockette) ((char*)((uint8_t*)blockette+24))
#define pMS2B500_CLOCKMODEL(blockette) ((char*)((uint8_t*)blockette+40))
#define pMS2B500_CLOCKSTATUS(blockette) ((char*)((uint8_t*)blockette+72))
/***************************************************************************
* miniSEED 2.4 Blockette 1000 - data only SEED (miniSEED)
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* encoding uint8_t 4
* byteorder uint8_t 5
* reclen uint8_t 6
* reserved uint8_t 7
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B1000_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B1000_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B1000_ENCODING(blockette) ((uint8_t*)((uint8_t*)blockette+4))
#define pMS2B1000_BYTEORDER(blockette) ((uint8_t*)((uint8_t*)blockette+5))
#define pMS2B1000_RECLEN(blockette) ((uint8_t*)((uint8_t*)blockette+6))
#define pMS2B1000_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+7))
/***************************************************************************
* miniSEED 2.4 Blockette 1001 - data extension
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* timing quality uint8_t 4
* microsecond int8_t 5
* reserved uint8_t 6
* frame count uint8_t 7
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B1001_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B1001_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B1001_TIMINGQUALITY(blockette) ((uint8_t*)((uint8_t*)blockette+4))
#define pMS2B1001_MICROSECOND(blockette) ((int8_t*)((uint8_t*)blockette+5))
#define pMS2B1001_RESERVED(blockette) ((uint8_t*)((uint8_t*)blockette+6))
#define pMS2B1001_FRAMECOUNT(blockette) ((uint8_t*)((uint8_t*)blockette+7))
/***************************************************************************
* miniSEED 2.4 Blockette 2000 - opaque data
*
* FIELD TYPE OFFSET
* type uint16_t 0
* next offset uint16_t 2
* length uint16_t 4
* data offset uint16_t 6
* recnum uint32_t 8
* byteorder uint8_t 12
* flags uint8_t 13
* numheaders uint8_t 14
* payload char[1] 15
*
* Convenience macros for accessing the fields via typed pointers follow:
***************************************************************************/
#define pMS2B2000_TYPE(blockette) ((uint16_t*)(blockette))
#define pMS2B2000_NEXT(blockette) ((uint16_t*)((uint8_t*)blockette+2))
#define pMS2B2000_LENGTH(blockette) ((uint16_t*)((uint8_t*)blockette+4))
#define pMS2B2000_DATAOFFSET(blockette) ((uint16_t*)((uint8_t*)blockette+6))
#define pMS2B2000_RECNUM(blockette) ((uint32_t*)((uint8_t*)blockette+8))
#define pMS2B2000_BYTEORDER(blockette) ((uint8_t*)((uint8_t*)blockette+12))
#define pMS2B2000_FLAGS(blockette) ((uint8_t*)((uint8_t*)blockette+13))
#define pMS2B2000_NUMHEADERS(blockette) ((uint8_t*)((uint8_t*)blockette+14))
#define pMS2B2000_PAYLOAD(blockette) ((char*)((uint8_t*)blockette+15))
/***************************************************************************
* Simple static inline convenience functions to swap bytes to "host
* order", as determined by the swap flag.
***************************************************************************/
static inline int16_t
HO2d (int16_t value, int swapflag)
{
if (swapflag)
{
ms_gswap2 (&value);
}
return value;
}
static inline uint16_t
HO2u (uint16_t value, int swapflag)
{
if (swapflag)
{
ms_gswap2 (&value);
}
return value;
}
static inline int32_t
HO4d (int32_t value, int swapflag)
{
if (swapflag)
{
ms_gswap4 (&value);
}
return value;
}
static inline uint32_t
HO4u (uint32_t value, int swapflag)
{
if (swapflag)
{
ms_gswap4 (&value);
}
return value;
}
static inline float
HO4f (float value, int swapflag)
{
if (swapflag)
{
ms_gswap4 (&value);
}
return value;
}
static inline double
HO8f (double value, int swapflag)
{
if (swapflag)
{
ms_gswap8 (&value);
}
return value;
}
/* Macro to test for sane year and day values, used primarily to
* determine if byte order swapping is needed for miniSEED 2.x.
*
* Year : between 1900 and 2100
* Day : between 1 and 366
*
* This test is non-unique (non-deterministic) for days 1, 256 and 257
* in the year 2056 because the swapped values are also within range.
* If you are using this in 2056 to determine the byte order of miniSEED 2
* you have my deepest sympathies.
*/
#define MS_ISVALIDYEARDAY(Y,D) (Y >= 1900 && Y <= 2100 && D >= 1 && D <= 366)
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,830 @@
/***************************************************************************
* I/O handling routines, for files and URLs.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
/* Define _LARGEFILE_SOURCE to get ftello/fseeko on some systems (Linux) */
#define _LARGEFILE_SOURCE 1
#include <errno.h>
#include "msio.h"
/* Include libcurl library header if URL supported is requested */
#if defined(LIBMSEED_URL)
#include <curl/curl.h>
/* Control for enabling debugging information */
int libmseed_url_debug = -1;
/* Control for SSL peer and host verification */
long libmseed_ssl_noverify = -1;
/* A global libcurl easy handle for configuration options */
CURL *gCURLeasy = NULL;
/* A global libcurl list of headers */
struct curl_slist *gCURLheaders = NULL;
/* Receving callback parameters */
struct recv_callback_parameters
{
char *buffer;
size_t size;
int is_paused;
};
/* Header callback parameters */
struct header_callback_parameters
{
int64_t *startoffset;
int64_t *endoffset;
};
/*********************************************************************
* Callback fired when recv'ing data using libcurl.
*
* The destination buffer pointer and size in the callback parameters
* are adjusted as data are added.
*
* Returns number of bytes added to the destination buffer.
*********************************************************************/
static size_t
recv_callback (char *buffer, size_t size, size_t num, void *userdata)
{
struct recv_callback_parameters *rcp = (struct recv_callback_parameters *)userdata;
if (!buffer || !userdata)
return 0;
size *= num;
/* Pause connection if passed data does not fit into destination buffer */
if (size > rcp->size)
{
rcp->is_paused = 1;
return CURL_WRITEFUNC_PAUSE;
}
/* Otherwise, copy data to destination buffer */
else
{
memcpy (rcp->buffer, buffer, size);
rcp->buffer += size;
rcp->size -= size;
}
return size;
}
/*********************************************************************
* Callback fired when receiving headers using libcurl.
*
* Returns number of bytes processed for success.
*********************************************************************/
static size_t
header_callback (char *buffer, size_t size, size_t num, void *userdata)
{
struct header_callback_parameters *hcp = (struct header_callback_parameters *)userdata;
char startstr[21] = {0}; /* Maximum of 20 digit value */
char endstr[21] = {0}; /* Maximum of 20 digit value */
int startdigits = 0;
int enddigits = 0;
char *dash = NULL;
char *ptr;
if (!buffer || !userdata)
return 0;
size *= num;
/* Parse and store: "Content-Range: bytes START-END/TOTAL"
* e.g. Content-Range: bytes 512-1023/4096 */
if (size > 22 && strncasecmp (buffer, "Content-Range: bytes", 20) == 0)
{
/* Process each character, starting just afer "bytes" unit */
for (ptr = buffer + 20; *ptr != '\0' && (ptr - buffer) < size; ptr++)
{
/* Skip spaces before start of range */
if (*ptr == ' ' && startdigits == 0)
continue;
/* Digits before dash, part of start */
else if (isdigit (*ptr) && dash == NULL)
startstr[startdigits++] = *ptr;
/* Digits after dash, part of end */
else if (isdigit (*ptr) && dash != NULL)
endstr[enddigits++] = *ptr;
/* If first dash found, store pointer */
else if (*ptr == '-' && dash == NULL)
dash = ptr;
/* Nothing else is part of the range */
else
break;
/* If digit sequences have exceeded limits, not a valid range */
if (startdigits >= sizeof (startstr) || enddigits >= sizeof (endstr))
{
startdigits = 0;
enddigits = 0;
break;
}
}
/* Convert start and end values to numbers if non-zero length */
if (hcp->startoffset && startdigits)
*hcp->startoffset = (int64_t) strtoull (startstr, NULL, 10);
if (hcp->endoffset && enddigits)
*hcp->endoffset = (int64_t) strtoull (endstr, NULL, 10);
}
return size;
}
#endif /* defined(LIBMSEED_URL) */
/***************************************************************************
* msio_fopen:
*
* Determine if requested path is a regular file or a URL and open or
* initialize as appropriate.
*
* The 'mode' argument is only for file-system paths and ignored for
* URLs. If 'mode' is set to NULL, default is 'rb' mode.
*
* If 'startoffset' or 'endoffset' are non-zero they will be used to
* position the stream for reading, either setting the read position
* of a file or requesting a range via HTTP. These will be set to the
* actual range if reported via HTTP, which may be different than
* requested.
*
* Return 0 on success and -1 on error.
*
* \ref MessageOnError - this function logs a message on error
***************************************************************************/
int
msio_fopen (LMIO *io, const char *path, const char *mode,
int64_t *startoffset, int64_t *endoffset)
{
int knownfile = 0;
if (!io || !path)
return -1;
if (!mode)
mode = "rb";
/* Treat "file://" specifications as local files by removing the scheme */
if (!strncasecmp (path, "file://", 7))
{
path += 7;
knownfile = 1;
}
/* Test for URL scheme via "://" */
if (!knownfile && strstr (path, "://"))
{
#if !defined(LIBMSEED_URL)
ms_log (2, "URL support not included in library for %s\n", path);
return -1;
#else
long response_code;
struct header_callback_parameters hcp;
io->type = LMIO_URL;
/* Check for URL debugging environment variable */
if (libmseed_url_debug < 0)
{
if (getenv ("LIBMSEED_URL_DEBUG"))
libmseed_url_debug = 1;
else
libmseed_url_debug = 0;
}
/* Check for SSL peer/host verify environment variable */
if (libmseed_ssl_noverify < 0)
{
if (getenv ("LIBMSEED_SSL_NOVERIFY"))
libmseed_ssl_noverify = 1;
else
libmseed_ssl_noverify = 0;
}
/* Configure the libcurl easy handle, duplicate global options if present */
io->handle = (gCURLeasy) ? curl_easy_duphandle (gCURLeasy) : curl_easy_init ();
if (io->handle == NULL)
{
ms_log (2, "Cannot initialize CURL handle\n");
return -1;
}
/* URL debug */
if (libmseed_url_debug && curl_easy_setopt (io->handle, CURLOPT_VERBOSE, 1L) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_VERBOSE\n");
return -1;
}
/* SSL peer and host verification */
if (libmseed_ssl_noverify &&
(curl_easy_setopt (io->handle, CURLOPT_SSL_VERIFYPEER, 0L) != CURLE_OK ||
curl_easy_setopt (io->handle, CURLOPT_SSL_VERIFYHOST, 0L) != CURLE_OK))
{
ms_log (2, "Cannot set CURLOPT_SSL_VERIFYPEER and/or CURLOPT_SSL_VERIFYHOST\n");
return -1;
}
/* Set URL */
if (curl_easy_setopt (io->handle, CURLOPT_URL, path) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_URL\n");
return -1;
}
/* Set default User-Agent header, can be overridden via custom header */
if (curl_easy_setopt (io->handle, CURLOPT_USERAGENT,
"libmseed/" LIBMSEED_VERSION " libcurl/" LIBCURL_VERSION) != CURLE_OK)
{
ms_log (2, "Cannot set default CURLOPT_USERAGENT\n");
return -1;
}
/* Disable signals */
if (curl_easy_setopt (io->handle, CURLOPT_NOSIGNAL, 1L) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_NOSIGNAL\n");
return -1;
}
/* Return failure codes on errors */
if (curl_easy_setopt (io->handle, CURLOPT_FAILONERROR, 1L) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_FAILONERROR\n");
return -1;
}
/* Follow HTTP redirects */
if (curl_easy_setopt (io->handle, CURLOPT_FOLLOWLOCATION, 1L) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_FOLLOWLOCATION\n");
return -1;
}
/* Configure write callback for recv'ed data */
if (curl_easy_setopt (io->handle, CURLOPT_WRITEFUNCTION, recv_callback) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_WRITEFUNCTION\n");
return -1;
}
/* Configure the libcurl multi handle, for use with the asynchronous interface */
if ((io->handle2 = curl_multi_init ()) == NULL)
{
ms_log (2, "Cannot initialize CURL multi handle\n");
return -1;
}
if (curl_multi_add_handle (io->handle2, io->handle) != CURLM_OK)
{
ms_log (2, "Cannot add CURL handle to multi handle\n");
return -1;
}
/* Set byte ranging */
if ((startoffset && *startoffset > 0) || (endoffset && *endoffset > 0))
{
char startstr[21] = {0};
char endstr[21] = {0};
char rangestr[42];
/* Build Range header value.
* If start is undefined set it to zero if end is defined. */
if (*startoffset > 0)
snprintf (startstr, sizeof (startstr), "%" PRId64, *startoffset);
else if (*endoffset > 0)
snprintf (startstr, sizeof (startstr), "0");
if (*endoffset > 0)
snprintf (endstr, sizeof (endstr), "%" PRId64, *endoffset);
snprintf (rangestr, sizeof (rangestr), "%s-%s", startstr, endstr);
/* Set Range header */
if (curl_easy_setopt (io->handle, CURLOPT_RANGE, rangestr) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_RANGE to '%s'\n", rangestr);
return -1;
}
}
/* Set up header callback */
if (startoffset || endoffset)
{
hcp.startoffset = startoffset;
hcp.endoffset = endoffset;
/* Configure header callback */
if (curl_easy_setopt (io->handle, CURLOPT_HEADERFUNCTION, header_callback) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_HEADERFUNCTION\n");
return -1;
}
if (curl_easy_setopt (io->handle, CURLOPT_HEADERDATA, (void *)&hcp) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_HEADERDATA\n");
return -1;
}
}
/* Set custom headers */
if (gCURLheaders && curl_easy_setopt (io->handle, CURLOPT_HTTPHEADER, gCURLheaders) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_HTTPHEADER\n");
return -1;
}
/* Set connection as still running */
io->still_running = 1;
/* Start connection, get status & headers, without consuming any data */
msio_fread (io, NULL, 0);
curl_easy_getinfo (io->handle, CURLINFO_RESPONSE_CODE, &response_code);
if (response_code == 404)
{
ms_log (2, "Cannot open %s: Not Found (404)\n", path);
return -1;
}
else if (response_code >= 400 && response_code < 600)
{
ms_log (2, "Cannot open %s: response code %ld\n", path, response_code);
return -1;
}
#endif /* defined(LIBMSEED_URL) */
}
else
{
io->type = LMIO_FILE;
if ((io->handle = fopen (path, mode)) == NULL)
{
ms_log (2, "Cannot open: %s (%s)\n", path, strerror(errno));
return -1;
}
/* Seek to position if start offset is provided */
if (startoffset && *startoffset > 0)
{
if (lmp_fseek64 (io->handle, *startoffset, SEEK_SET))
{
ms_log (2, "Cannot seek in %s to offset %" PRId64 "\n", path, *startoffset);
return -1;
}
}
}
return 0;
} /* End of msio_fopen() */
/*********************************************************************
* msio_fclose:
*
* Close an IO handle.
*
* Returns 0 on success and negative value on error.
*
* \ref MessageOnError - this function logs a message on error
*********************************************************************/
int
msio_fclose (LMIO *io)
{
int rv;
if (!io)
{
ms_log (2, "Required argument not defined: 'io'\n");
return -1;
}
if (io->handle == NULL || io->type == LMIO_NULL)
return 0;
if (io->type == LMIO_FILE)
{
rv = fclose (io->handle);
if (rv)
{
ms_log (2, "Error closing file (%s)\n", strerror(errno));
return -1;
}
}
else if (io->type == LMIO_URL)
{
#if !defined(LIBMSEED_URL)
ms_log (2, "URL support not included in library\n");
return -1;
#else
curl_multi_remove_handle (io->handle2, io->handle);
curl_easy_cleanup (io->handle);
curl_multi_cleanup (io->handle2);
#endif
}
io->type = LMIO_NULL;
io->handle = NULL;
io->handle2 = NULL;
return 0;
} /* End of msio_fclose() */
/*********************************************************************
* msio_fread:
*
* Read data from the identified IO handle into the specified buffer.
* Up to the requested 'size' bytes are read.
*
* For URL support, with defined(LIBMSEED_URL), the destination
* receive buffer MUST be at least as big as the curl receive buffer
* (CURLOPT_BUFFERSIZE, which defaults to CURL_MAX_WRITE_SIZE of 16kB)
* or the maximum size of a retrieved object if less than
* CURL_MAX_WRITE_SIZE. The caller must ensure this.
*
* Returns the number of bytes read on success and a negative value on
* error.
*********************************************************************/
size_t
msio_fread (LMIO *io, void *buffer, size_t size)
{
size_t read = 0;
if (!io)
return -1;
if (!buffer && size > 0)
{
ms_log (2, "No buffer specified for size is > 0\n");
return -1;
}
/* Read from regular file stream */
if (io->type == LMIO_FILE)
{
read = fread (buffer, 1, size, io->handle);
}
/* Read from URL stream */
else if (io->type == LMIO_URL)
{
#if !defined(LIBMSEED_URL)
ms_log (2, "URL support not included in library\n");
return -1;
#else
struct recv_callback_parameters rcp;
struct timeval timeout;
fd_set fdread;
fd_set fdwrite;
fd_set fdexcep;
long curl_timeo = -1;
int maxfd = -1;
int rc;
if (!io->still_running)
return 0;
/* Set up destination buffer in write callback parameters */
rcp.buffer = buffer;
rcp.size = size;
if (curl_easy_setopt (io->handle, CURLOPT_WRITEDATA, (void *)&rcp) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_WRITEDATA\n");
return -1;
}
/* Unpause connection */
curl_easy_pause (io->handle, CURLPAUSE_CONT);
rcp.is_paused = 0;
/* Receive data while connection running, destination space available
* and connection is not paused. */
do
{
/* Default timeout for read failure */
timeout.tv_sec = 60;
timeout.tv_usec = 0;
curl_multi_timeout (io->handle2, &curl_timeo);
/* Tailor timeout based on maximum suggested by libcurl */
if (curl_timeo >= 0)
{
timeout.tv_sec = curl_timeo / 1000;
if (timeout.tv_sec > 1)
timeout.tv_sec = 1;
else
timeout.tv_usec = (curl_timeo % 1000) * 1000;
}
FD_ZERO (&fdread);
FD_ZERO (&fdwrite);
FD_ZERO (&fdexcep);
/* Extract descriptors from the multi-handle */
if (curl_multi_fdset (io->handle2, &fdread, &fdwrite, &fdexcep, &maxfd) != CURLM_OK)
{
ms_log (2, "Error with curl_multi_fdset()\n");
return -1;
}
/* libcurl/system needs time to work, sleep 100 milliseconds */
if (maxfd == -1)
{
lmp_nanosleep (100000000);
rc = 0;
}
else
{
rc = select (maxfd + 1, &fdread, &fdwrite, &fdexcep, &timeout);
}
/* Receive data */
if (rc >= 0)
{
curl_multi_perform (io->handle2, &io->still_running);
}
} while (io->still_running > 0 && !rcp.is_paused && (rcp.size > 0 || rcp.buffer == NULL));
read = size - rcp.size;
#endif /* defined(LIBMSEED_URL) */
}
return read;
} /* End of msio_fread() */
/*********************************************************************
* msio_feof:
*
* Test if end-of-stream.
*
* Returns 1 when stream is at end, 0 if not, and -1 on error.
*********************************************************************/
int
msio_feof (LMIO *io)
{
if (!io)
return 0;
if (io->handle == NULL || io->type == LMIO_NULL)
return 0;
if (io->type == LMIO_FILE)
{
if (feof ((FILE *)io->handle))
return 1;
}
else if (io->type == LMIO_URL)
{
#if !defined(LIBMSEED_URL)
ms_log (2, "URL support not included in library\n");
return -1;
#else
/* The still_running flag is only changed by curl_multi_perform()
* and indicates current "transfers in progress". Presumably no data
* are in internal libcurl buffers either. */
if (!io->still_running)
return 1;
#endif
}
return 0;
} /* End of msio_feof() */
/*********************************************************************
* msio_url_useragent:
*
* Set global User-Agent header for URL-based IO.
*
* The header is built as "PROGRAM/VERSION libmseed/version libcurl/version"
* where VERSION is optional.
*
* Returns 0 on succes non-zero otherwise.
*
* \ref MessageOnError - this function logs a message on error
*********************************************************************/
int
msio_url_useragent (const char *program, const char *version)
{
if (!program)
{
ms_log (2, "Required argument not defined: 'program'\n");
return -1;
}
#if !defined(LIBMSEED_URL)
ms_log (2, "URL support not included in library\n");
return -1;
#else
char header[1024];
/* Build User-Agent header and add internal versions */
snprintf (header, sizeof (header),
"User-Agent: %s%s%s libmseed/" LIBMSEED_VERSION " libcurl/" LIBCURL_VERSION,
program,
(version) ? "/" : "",
(version) ? version : "");
return msio_url_addheader (header);
#endif
return 0;
} /* End of msio_url_useragent() */
/*********************************************************************
* msio_url_userpassword:
*
* Set global user-password credentials for URL-based IO.
*
* Returns 0 on succes non-zero otherwise.
*
* \ref MessageOnError - this function logs a message on error
*********************************************************************/
int
msio_url_userpassword (const char *userpassword)
{
if (!userpassword)
{
ms_log (2, "Required argument not defined: 'userpassword'\n");
return -1;
}
#if !defined(LIBMSEED_URL)
ms_log (2, "URL support not included in library\n");
return -1;
#else
if (gCURLeasy == NULL && (gCURLeasy = curl_easy_init ()) == NULL)
return -1;
/* Allow any authentication, libcurl will pick the most secure */
if (curl_easy_setopt (gCURLeasy, CURLOPT_HTTPAUTH, CURLAUTH_ANY) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_HTTPAUTH\n");
return -1;
}
if (curl_easy_setopt (gCURLeasy, CURLOPT_USERPWD, userpassword) != CURLE_OK)
{
ms_log (2, "Cannot set CURLOPT_USERPWD\n");
return -1;
}
#endif
return 0;
} /* End of msio_url_userpassword() */
/*********************************************************************
* msio_url_addheader:
*
* Add header to global list for URL-based IO.
*
* Returns 0 on succes non-zero otherwise.
*
* \ref MessageOnError - this function logs a message on error
*********************************************************************/
int
msio_url_addheader (const char *header)
{
if (!header)
{
ms_log (2, "Required argument not defined: 'header'\n");
return -1;
}
#if !defined(LIBMSEED_URL)
ms_log (2, "URL support not included in library\n");
return -1;
#else
struct curl_slist *slist = NULL;
slist = curl_slist_append (gCURLheaders, header);
if (slist == NULL)
{
ms_log (2, "Error adding header to list: %s\n", header);
return -1;
}
gCURLheaders = slist;
#endif
return 0;
} /* End of msio_url_addheader() */
/*********************************************************************
* msio_url_freeheaders:
*
* Free the global list of headers for URL-based IO.
*********************************************************************/
void
msio_url_freeheaders (void)
{
#if !defined(LIBMSEED_URL)
ms_log (2, "URL support not included in library\n");
return;
#else
if (gCURLheaders != NULL)
{
curl_slist_free_all (gCURLheaders);
gCURLheaders = NULL;
}
#endif
} /* End of msio_url_freeheaders() */
/***************************************************************************
* lmp_ftell64:
*
* Return the current file position for the specified descriptor using
* the system's closest match to the POSIX ftello().
***************************************************************************/
int64_t
lmp_ftell64 (FILE *stream)
{
#if defined(LMP_WIN)
return (int64_t)_ftelli64 (stream);
#else
return (int64_t)ftello (stream);
#endif
} /* End of lmp_ftell64() */
/***************************************************************************
* lmp_fseek64:
*
* Seek to a specific file position for the specified descriptor using
* the system's closest match to the POSIX fseeko().
***************************************************************************/
int
lmp_fseek64 (FILE *stream, int64_t offset, int whence)
{
#if defined(LMP_WIN)
return (int)_fseeki64 (stream, offset, whence);
#else
return (int)fseeko (stream, offset, whence);
#endif
} /* End of lmp_fseeko() */
/***************************************************************************
* @brief Sleep for a specified number of nanoseconds
*
* Sleep for a given number of nanoseconds. Under WIN use SleepEx()
* and is limited to millisecond resolution. For all others use the
* POSIX.4 nanosleep(), which can be interrupted by signals.
*
* @param nanoseconds Nanoseconds to sleep
*
* @return On non-WIN: the remaining nanoseconds are returned if the
* requested interval is interrupted.
***************************************************************************/
uint64_t
lmp_nanosleep (uint64_t nanoseconds)
{
#if defined(LMP_WIN)
/* SleepEx is limited to milliseconds */
SleepEx ((DWORD) (nanoseconds / 1e6), 1);
return 0;
#else
struct timespec treq, trem;
treq.tv_sec = (time_t) (nanoseconds / 1e9);
treq.tv_nsec = (long)(nanoseconds - (uint64_t)treq.tv_sec * 1e9);
nanosleep (&treq, &trem);
return trem.tv_sec * 1e9 + trem.tv_nsec;
#endif
} /* End of lmp_nanosleep() */

@ -0,0 +1,44 @@
/***************************************************************************
* Interface declarations for routines in fio.c
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#ifndef MSIO_H
#define MSIO_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include "libmseed.h"
extern int msio_fopen (LMIO *io, const char *path, const char *mode,
int64_t *startoffset, int64_t *endoffset);
extern int msio_fclose (LMIO *io);
extern size_t msio_fread (LMIO *io, void *buffer, size_t size);
extern int msio_feof (LMIO *io);
extern int msio_url_useragent (const char *program, const char *version);
extern int msio_url_userpassword (const char *userpassword);
extern int msio_url_addheader (const char *header);
extern void msio_url_freeheaders (void);
#ifdef __cplusplus
}
#endif
#endif

@ -0,0 +1,395 @@
/***************************************************************************
* Generic routines to operate on miniSEED records.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "libmseed.h"
/**********************************************************************/ /**
* @brief Initialize and return an ::MS3Record
*
* Memory is allocated if for a new ::MS3Record if \a msr is NULL.
*
* If memory for the \c datasamples field has been allocated the pointer
* will be retained for reuse. If memory for extra headers has been
* allocated it will be released.
*
* @param[in] msr A ::MS3Record to re-initialize
*
* @returns a pointer to a ::MS3Record struct on success or NULL on error.
*
* \ref MessageOnError - this function logs a message on error
***************************************************************************/
MS3Record *
msr3_init (MS3Record *msr)
{
void *datasamples = NULL;
size_t datasize = 0;
if (!msr)
{
msr = (MS3Record *)libmseed_memory.malloc (sizeof (MS3Record));
}
else
{
datasamples = msr->datasamples;
datasize = msr->datasize;
if (msr->extra)
libmseed_memory.free (msr->extra);
}
if (msr == NULL)
{
ms_log (2, "Cannot allocate memory\n");
return NULL;
}
memset (msr, 0, sizeof (MS3Record));
msr->datasamples = datasamples;
msr->datasize = datasize;
msr->reclen = -1;
msr->samplecnt = -1;
msr->encoding = -1;
return msr;
} /* End of msr3_init() */
/**********************************************************************/ /**
* @brief Free all memory associated with a ::MS3Record
*
* Free all memory associated with a ::MS3Record, including extra
* header and data samples if present.
*
* @param[in] ppmsr Pointer to point of the ::MS3Record to free
***************************************************************************/
void
msr3_free (MS3Record **ppmsr)
{
if (ppmsr != NULL && *ppmsr != 0)
{
if ((*ppmsr)->extra)
libmseed_memory.free ((*ppmsr)->extra);
if ((*ppmsr)->datasamples)
libmseed_memory.free ((*ppmsr)->datasamples);
libmseed_memory.free (*ppmsr);
*ppmsr = NULL;
}
} /* End of msr3_free() */
/**********************************************************************/ /**
* @brief Duplicate a ::MS3Record
*
* Extra headers are duplicated as well.
*
* If the \a datadup flag is true (non-zero) and the source
* ::MS3Record has associated data samples copy them as well.
*
* @param[in] msr ::MS3Record to duplicate
* @param[in] datadup Flag to control duplication of data samples
*
* @returns Pointer to a new ::MS3Record on success and NULL on error
*
* \ref MessageOnError - this function logs a message on error
***************************************************************************/
MS3Record *
msr3_duplicate (const MS3Record *msr, int8_t datadup)
{
MS3Record *dupmsr = 0;
if (!msr)
{
ms_log (2, "Required argument not defined: 'msr'\n");
return NULL;
}
/* Allocate target MS3Record structure */
if ((dupmsr = msr3_init (NULL)) == NULL)
return NULL;
/* Copy MS3Record structure */
memcpy (dupmsr, msr, sizeof (MS3Record));
/* Disconnect pointers from the source structure and reference values */
dupmsr->extra = NULL;
dupmsr->extralength = 0;
dupmsr->datasamples = NULL;
dupmsr->datasize = 0;
dupmsr->numsamples = 0;
/* Copy extra headers */
if (msr->extralength > 0 && msr->extra)
{
/* Allocate memory for new FSDH structure */
if ((dupmsr->extra = (char *)libmseed_memory.malloc (msr->extralength)) == NULL)
{
ms_log (2, "Error allocating memory\n");
msr3_free (&dupmsr);
return NULL;
}
memcpy (dupmsr->extra, msr->extra, msr->extralength);
if (dupmsr->extra)
dupmsr->extralength = msr->extralength;
}
/* Copy data samples if requested and available */
if (datadup && msr->numsamples > 0 && msr->datasize > 0 && msr->datasamples)
{
/* Allocate memory for new data array */
if ((dupmsr->datasamples = libmseed_memory.malloc ((size_t) (msr->datasize))) == NULL)
{
ms_log (2, "Error allocating memory\n");
msr3_free (&dupmsr);
return NULL;
}
memcpy (dupmsr->datasamples, msr->datasamples, msr->datasize);
if (dupmsr->datasamples)
{
dupmsr->datasize = msr->datasize;
dupmsr->numsamples = msr->numsamples;
}
}
return dupmsr;
} /* End of msr3_duplicate() */
/**********************************************************************/ /**
* @brief Calculate time of the last sample in a record
*
* If leap seconds have been loaded into the internal library list:
* when a record completely contains a leap second, starts before and
* ends after, the calculated end time will be adjusted (reduced) by
* one second.
* @note On the epoch time scale the value of a leap second is the
* same as the second following the leap second, without external
* information the values are ambiguous.
* \sa ms_readleapsecondfile()
*
* @param[in] msr ::MS3Record to calculate end time of
*
* @returns Time of the last sample on success and NSTERROR on error.
***************************************************************************/
nstime_t
msr3_endtime (const MS3Record *msr)
{
int64_t sampleoffset = 0;
if (!msr)
return NSTERROR;
if (msr->samplecnt > 0)
sampleoffset = msr->samplecnt - 1;
return ms_sampletime (msr->starttime, sampleoffset, msr->samprate);
} /* End of msr3_endtime() */
/**********************************************************************/ /**
* @brief Print header values of an MS3Record
*
* @param[in] msr ::MS3Record to print
* @param[in] details Flags to control the level of details:
* @parblock
* - \c 0 - print a single summary line
* - \c 1 - print most details of header
* - \c >1 - print all details of header and extra headers if present
* @endparblock
***************************************************************************/
void
msr3_print (const MS3Record *msr, int8_t details)
{
char time[40];
char b;
if (!msr)
return;
/* Generate a start time string */
ms_nstime2timestr (msr->starttime, time, ISOMONTHDAY_DOY_Z, NANO_MICRO);
/* Report information in the fixed header */
if (details > 0)
{
ms_log (0, "%s, version %d, %d bytes (format: %d)\n",
msr->sid, msr->pubversion, msr->reclen, msr->formatversion);
ms_log (0, " start time: %s\n", time);
ms_log (0, " number of samples: %" PRId64 "\n", msr->samplecnt);
ms_log (0, " sample rate (Hz): %.10g\n", msr3_sampratehz(msr));
if (details > 1)
{
b = msr->flags;
ms_log (0, " flags: [%d%d%d%d%d%d%d%d] 8 bits\n",
bit (b, 0x80), bit (b, 0x40), bit (b, 0x20), bit (b, 0x10),
bit (b, 0x08), bit (b, 0x04), bit (b, 0x02), bit (b, 0x01));
if (b & 0x01)
ms_log (0, " [Bit 0] Calibration signals present\n");
if (b & 0x02)
ms_log (0, " [Bit 1] Time tag is questionable\n");
if (b & 0x04)
ms_log (0, " [Bit 2] Clock locked\n");
if (b & 0x08)
ms_log (0, " [Bit 3] Undefined bit set\n");
if (b & 0x10)
ms_log (0, " [Bit 4] Undefined bit set\n");
if (b & 0x20)
ms_log (0, " [Bit 5] Undefined bit set\n");
if (b & 0x40)
ms_log (0, " [Bit 6] Undefined bit set\n");
if (b & 0x80)
ms_log (0, " [Bit 7] Undefined bit set\n");
}
ms_log (0, " CRC: 0x%0X\n", msr->crc);
ms_log (0, " extra header length: %d bytes\n", msr->extralength);
ms_log (0, " data payload length: %d bytes\n", msr->datalength);
ms_log (0, " payload encoding: %s (val: %d)\n",
(char *)ms_encodingstr (msr->encoding), msr->encoding);
if (details > 1 && msr->extralength > 0 && msr->extra)
{
ms_log (0, " extra headers:\n");
mseh_print (msr, 16);
}
}
else
{
ms_log (0, "%s, %d, %d, %" PRId64 " samples, %-.10g Hz, %s\n",
msr->sid, msr->pubversion, msr->reclen,
msr->samplecnt, msr3_sampratehz(msr), time);
}
} /* End of msr3_print() */
/**********************************************************************/ /**
* @brief Resize data sample buffer of ::MS3Record to what is needed
*
* This routine should only be used if pre-allocation of memory, via
* ::libmseed_prealloc_block_size, was enabled to allocate the buffer.
*
* @param[in] msr ::MS3Record to resize buffer
*
* @returns Return 0 on success, otherwise returns a libmseed error code.
*
* \ref MessageOnError - this function logs a message on error
***************************************************************************/
int
msr3_resize_buffer (MS3Record *msr)
{
uint8_t samplesize = 0;
size_t datasize;
if (!msr)
{
ms_log (2, "Required argument not defined: 'msr'\n");
return MS_GENERROR;
}
samplesize = ms_samplesize(msr->sampletype);
if (samplesize && msr->datasamples && msr->numsamples > 0)
{
datasize = (size_t) msr->numsamples * samplesize;
if (msr->datasize > datasize)
{
msr->datasamples = libmseed_memory.realloc (msr->datasamples, datasize);
if (msr->datasamples == NULL)
{
ms_log (2, "%s: Cannot (re)allocate memory\n", msr->sid);
return MS_GENERROR;
}
msr->datasize = datasize;
}
}
return 0;
} /* End of msr3_resize_buffer() */
/**********************************************************************/ /**
* @brief Calculate sample rate in samples/second (Hertz) for a given ::MS3Record
*
* @param[in] msr ::MS3Record to calculate sample rate for
*
* @returns Return sample rate in Hertz (samples per second)
***************************************************************************/
inline double
msr3_sampratehz (const MS3Record *msr)
{
if (!msr)
return 0.0;
if (msr->samprate < 0.0)
return (-1.0 / msr->samprate);
else
return msr->samprate;
} /* End of msr3_sampratehz() */
/**********************************************************************/ /**
* @brief Calculate data latency based on the host time
*
* Calculation is based on the time of the last sample in the record; in
* other words, the difference between the host time and the time of
* the last sample in the record.
*
* Double precision is returned, but the true precision is dependent
* on the accuracy of the host system clock among other things.
*
* @param[in] msr ::MS3Record to calculate lactency for
*
* @returns seconds of latency or 0.0 on error (indistinguishable from
* 0.0 latency).
***************************************************************************/
double
msr3_host_latency (const MS3Record *msr)
{
double span = 0.0; /* Time covered by the samples */
double epoch; /* Current epoch time */
double latency = 0.0;
time_t tv;
if (msr == NULL)
return 0.0;
/* Calculate the time covered by the samples */
if (msr->samprate > 0.0 && msr->samplecnt > 0)
span = (1.0 / msr->samprate) * (msr->samplecnt - 1);
/* Grab UTC time according to the system clock */
epoch = (double)time (&tv);
/* Now calculate the latency */
latency = epoch - ((double)msr->starttime / NSTMODULUS) - span;
return latency;
} /* End of msr3_host_latency() */

File diff suppressed because it is too large Load Diff

@ -0,0 +1,722 @@
/***********************************************************************
* Routines for packing Text, INT_16, INT_32, FLOAT_32, FLOAT_64,
* STEIM1 and STEIM2 data records.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
************************************************************************/
#include <memory.h>
#include <stdio.h>
#include <stdlib.h>
#include "libmseed.h"
#include "packdata.h"
/************************************************************************
* msr_encode_text:
*
* Encode text data and place in supplied buffer.
*
* Return number of samples in output buffer on success, -1 on failure.
************************************************************************/
int
msr_encode_text (char *input, int samplecount, char *output,
int outputlength)
{
int length;
if (samplecount <= 0)
return 0;
if (!input || !output || outputlength <= 0)
return -1;
/* Determine minimum of input or output */
length = (samplecount < outputlength) ? samplecount : outputlength;
memcpy (output, input, length);
return length;
} /* End of msr_encode_text() */
/************************************************************************
* msr_encode_int16:
*
* Encode 16-bit integer data from an array of 32-bit integers and
* place in supplied buffer. Swap if requested.
*
* Return number of samples in output buffer on success, -1 on failure.
************************************************************************/
int
msr_encode_int16 (int32_t *input, int samplecount, int16_t *output,
int outputlength, int swapflag)
{
int idx;
if (samplecount <= 0)
return 0;
if (!input || !output || outputlength <= 0)
return -1;
for (idx = 0; idx < samplecount && outputlength >= (int)sizeof (int16_t); idx++)
{
output[idx] = (int16_t)input[idx];
if (swapflag)
ms_gswap2 (&output[idx]);
outputlength -= sizeof (int16_t);
}
return idx;
} /* End of msr_encode_int16() */
/************************************************************************
* msr_encode_int32:
*
* Encode 32-bit integer data from an array of 32-bit integers and
* place in supplied buffer. Swap if requested.
*
* Return number of samples in output buffer on success, -1 on failure.
************************************************************************/
int
msr_encode_int32 (int32_t *input, int samplecount, int32_t *output,
int outputlength, int swapflag)
{
int idx;
if (samplecount <= 0)
return 0;
if (!input || !output || outputlength <= 0)
return -1;
for (idx = 0; idx < samplecount && outputlength >= (int)sizeof (int32_t); idx++)
{
output[idx] = input[idx];
if (swapflag)
ms_gswap4 (&output[idx]);
outputlength -= sizeof (int32_t);
}
return idx;
} /* End of msr_encode_int32() */
/************************************************************************
* msr_encode_float32:
*
* Encode 32-bit float data from an array of 32-bit floats and place
* in supplied buffer. Swap if requested.
*
* Return number of samples in output buffer on success, -1 on failure.
************************************************************************/
int
msr_encode_float32 (float *input, int samplecount, float *output,
int outputlength, int swapflag)
{
int idx;
if (samplecount <= 0)
return 0;
if (!input || !output || outputlength <= 0)
return -1;
for (idx = 0; idx < samplecount && outputlength >= (int)sizeof (float); idx++)
{
output[idx] = input[idx];
if (swapflag)
ms_gswap4 (&output[idx]);
outputlength -= sizeof (float);
}
return idx;
} /* End of msr_encode_float32() */
/************************************************************************
* msr_encode_float64:
*
* Encode 64-bit float data from an array of 64-bit doubles and place
* in supplied buffer. Swap if requested.
*
* Return number of samples in output buffer on success, -1 on failure.
************************************************************************/
int
msr_encode_float64 (double *input, int samplecount, double *output,
int outputlength, int swapflag)
{
int idx;
if (samplecount <= 0)
return 0;
if (!input || !output || outputlength <= 0)
return -1;
for (idx = 0; idx < samplecount && outputlength >= (int)sizeof (double); idx++)
{
output[idx] = input[idx];
if (swapflag)
ms_gswap8 (&output[idx]);
outputlength -= sizeof (double);
}
return idx;
} /* End of msr_encode_float64() */
/* Macro to determine number of bits needed to represent VALUE in
* the following bit widths: 4,5,6,8,10,15,16,30,32 and set RESULT. */
#define BITWIDTH(VALUE, RESULT) \
if (VALUE >= -8 && VALUE <= 7) \
RESULT = 4; \
else if (VALUE >= -16 && VALUE <= 15) \
RESULT = 5; \
else if (VALUE >= -32 && VALUE <= 31) \
RESULT = 6; \
else if (VALUE >= -128 && VALUE <= 127) \
RESULT = 8; \
else if (VALUE >= -512 && VALUE <= 511) \
RESULT = 10; \
else if (VALUE >= -16384 && VALUE <= 16383) \
RESULT = 15; \
else if (VALUE >= -32768 && VALUE <= 32767) \
RESULT = 16; \
else if (VALUE >= -536870912 && VALUE <= 536870911) \
RESULT = 30; \
else \
RESULT = 32;
/************************************************************************
* msr_encode_steim1:
*
* Encode Steim1 data frames from an array of 32-bit integers and
* place in supplied buffer. Swap if requested.
*
* diff0 is the first difference in the sequence and relates the first
* sample to the sample previous to it (not available to this
* function). It should be set to 0 if this value is not known.
*
* Return number of samples in output buffer on success, -1 on failure.
*
* \ref MessageOnError - this function logs a message on error
************************************************************************/
int
msr_encode_steim1 (int32_t *input, int samplecount, int32_t *output,
int outputlength, int32_t diff0, uint16_t *byteswritten,
int swapflag)
{
int32_t *frameptr; /* Frame pointer in output */
int32_t *Xnp = NULL; /* Reverse integration constant, aka last sample */
int32_t diffs[4];
int32_t bitwidth[4];
int diffcount = 0;
int inputidx = 0;
int outputsamples = 0;
int maxframes = outputlength / 64;
int packedsamples = 0;
int frameidx;
int startnibble;
int widx;
int idx;
union dword {
int8_t d8[4];
int16_t d16[2];
int32_t d32;
} * word;
if (samplecount <= 0)
return 0;
if (!input || !output || outputlength <= 0)
{
ms_log (2, "Required argument not defined: 'input', 'output' or 'outputlength' <= 0\n");
return -1;
}
#if ENCODE_DEBUG
ms_log (0, "Encoding Steim1 frames, samples: %d, max frames: %d, swapflag: %d\n",
samplecount, maxframes, swapflag);
#endif
/* Add first difference to buffers */
diffs[0] = diff0;
BITWIDTH (diffs[0], bitwidth[0]);
diffcount = 1;
for (frameidx = 0; frameidx < maxframes && outputsamples < samplecount; frameidx++)
{
frameptr = output + (16 * frameidx);
/* Set 64-byte frame to 0's */
memset (frameptr, 0, 64);
/* Save forward integration constant (X0), pointer to reverse integration constant (Xn)
* and set the starting nibble index depending on frame. */
if (frameidx == 0)
{
frameptr[1] = input[0];
if (swapflag)
ms_gswap4 (&frameptr[1]);
Xnp = &frameptr[2];
startnibble = 3; /* First frame: skip nibbles, X0, and Xn */
#if ENCODE_DEBUG
ms_log (0, "Frame %d: X0=%d\n", frameidx, input[0]);
#endif
}
else
{
startnibble = 1; /* Subsequent frames: skip nibbles */
#if ENCODE_DEBUG
ms_log (0, "Frame %d\n", frameidx);
#endif
}
for (widx = startnibble; widx < 16 && outputsamples < samplecount; widx++)
{
if (diffcount < 4)
{
/* Shift diffs and related bit widths to beginning of buffers */
for (idx = 0; idx < diffcount; idx++)
{
diffs[idx] = diffs[packedsamples + idx];
bitwidth[idx] = bitwidth[packedsamples + idx];
}
/* Add new diffs and determine bit width needed to represent */
for (idx = diffcount; idx < 4 && inputidx < (samplecount - 1); idx++, inputidx++)
{
diffs[idx] = *(input + inputidx + 1) - *(input + inputidx);
BITWIDTH (diffs[idx], bitwidth[idx]);
diffcount++;
}
}
/* Determine optimal packing by checking, in-order:
* 4 x 8-bit differences
* 2 x 16-bit differences
* 1 x 32-bit difference */
word = (union dword *)&frameptr[widx];
packedsamples = 0;
/* 4 x 8-bit differences */
if (diffcount == 4 &&
bitwidth[0] <= 8 && bitwidth[1] <= 8 &&
bitwidth[2] <= 8 && bitwidth[3] <= 8)
{
#if ENCODE_DEBUG
ms_log (0, " W%02d: 01=4x8b %d %d %d %d\n",
widx, diffs[0], diffs[1], diffs[2], diffs[3]);
#endif
word->d8[0] = diffs[0];
word->d8[1] = diffs[1];
word->d8[2] = diffs[2];
word->d8[3] = diffs[3];
/* 2-bit nibble is 0b01 (0x1) */
frameptr[0] |= 0x1ul << (30 - 2 * widx);
packedsamples = 4;
}
/* 2 x 16-bit differences */
else if (diffcount >= 2 &&
bitwidth[0] <= 16 && bitwidth[1] <= 16)
{
#if ENCODE_DEBUG
ms_log (0, " W%02d: 2=2x16b %d %d\n", widx, diffs[0], diffs[1]);
#endif
word->d16[0] = diffs[0];
word->d16[1] = diffs[1];
if (swapflag)
{
ms_gswap2 (&word->d16[0]);
ms_gswap2 (&word->d16[1]);
}
/* 2-bit nibble is 0b10 (0x2) */
frameptr[0] |= 0x2ul << (30 - 2 * widx);
packedsamples = 2;
}
/* 1 x 32-bit difference */
else
{
#if ENCODE_DEBUG
ms_log (0, " W%02d: 3=1x32b %d\n", widx, diffs[0]);
#endif
frameptr[widx] = diffs[0];
if (swapflag)
ms_gswap4 (&frameptr[widx]);
/* 2-bit nibble is 0b11 (0x3) */
frameptr[0] |= 0x3ul << (30 - 2 * widx);
packedsamples = 1;
}
diffcount -= packedsamples;
outputsamples += packedsamples;
} /* Done with words in frame */
/* Swap word with nibbles */
if (swapflag)
ms_gswap4 (&frameptr[0]);
} /* Done with frames */
/* Set Xn (reverse integration constant) in first frame to last sample */
if (Xnp)
*Xnp = *(input + outputsamples - 1);
if (swapflag)
ms_gswap4 (Xnp);
if (byteswritten)
*byteswritten = frameidx * 64;
return outputsamples;
} /* End of msr_encode_steim1() */
/************************************************************************
* msr_encode_steim2:
*
* Encode Steim2 data frames from an array of 32-bit integers and
* place in supplied buffer. Swap if requested.
*
* diff0 is the first difference in the sequence and relates the first
* sample to the sample previous to it (not available to this
* function). It should be set to 0 if this value is not known.
*
* Return number of samples in output buffer on success, -1 on failure.
*
* \ref MessageOnError - this function logs a message on error
************************************************************************/
int
msr_encode_steim2 (int32_t *input, int samplecount, int32_t *output,
int outputlength, int32_t diff0, uint16_t *byteswritten,
const char *sid, int swapflag)
{
uint32_t *frameptr; /* Frame pointer in output */
int32_t *Xnp = NULL; /* Reverse integration constant, aka last sample */
int32_t diffs[7];
int32_t bitwidth[7];
int diffcount = 0;
int inputidx = 0;
int outputsamples = 0;
int maxframes = outputlength / 64;
int packedsamples = 0;
int frameidx;
int startnibble;
int widx;
int idx;
union dword {
int8_t d8[4];
int16_t d16[2];
int32_t d32;
} * word;
if (samplecount <= 0)
return 0;
if (!input || !output || outputlength <= 0)
{
ms_log (2, "Required argument not defined: 'input', 'output' or 'outputlength' <= 0\n");
return -1;
}
#if ENCODE_DEBUG
ms_log (0, "Encoding Steim2 frames, samples: %d, max frames: %d, swapflag: %d\n",
samplecount, maxframes, swapflag);
#endif
/* Add first difference to buffers */
diffs[0] = diff0;
BITWIDTH (diffs[0], bitwidth[0]);
diffcount = 1;
for (frameidx = 0; frameidx < maxframes && outputsamples < samplecount; frameidx++)
{
frameptr = (uint32_t *)output + (16 * frameidx);
/* Set 64-byte frame to 0's */
memset (frameptr, 0, 64);
/* Save forward integration constant (X0), pointer to reverse integration constant (Xn)
* and set the starting nibble index depending on frame. */
if (frameidx == 0)
{
frameptr[1] = input[0];
#if ENCODE_DEBUG
ms_log (0, "Frame %d: X0=%d\n", frameidx, input[0]);
#endif
if (swapflag)
ms_gswap4 (&frameptr[1]);
Xnp = (int32_t *)&frameptr[2];
startnibble = 3; /* First frame: skip nibbles, X0, and Xn */
}
else
{
startnibble = 1; /* Subsequent frames: skip nibbles */
#if ENCODE_DEBUG
ms_log (0, "Frame %d\n", frameidx);
#endif
}
for (widx = startnibble; widx < 16 && outputsamples < samplecount; widx++)
{
if (diffcount < 7)
{
/* Shift diffs and related bit widths to beginning of buffers */
for (idx = 0; idx < diffcount; idx++)
{
diffs[idx] = diffs[packedsamples + idx];
bitwidth[idx] = bitwidth[packedsamples + idx];
}
/* Add new diffs and determine bit width needed to represent */
for (idx = diffcount; idx < 7 && inputidx < (samplecount - 1); idx++, inputidx++)
{
diffs[idx] = *(input + inputidx + 1) - *(input + inputidx);
BITWIDTH (diffs[idx], bitwidth[idx]);
diffcount++;
}
}
/* Determine optimal packing by checking, in-order:
* 7 x 4-bit differences
* 6 x 5-bit differences
* 5 x 6-bit differences
* 4 x 8-bit differences
* 3 x 10-bit differences
* 2 x 15-bit differences
* 1 x 30-bit difference */
packedsamples = 0;
/* 7 x 4-bit differences */
if (diffcount == 7 && bitwidth[0] <= 4 &&
bitwidth[1] <= 4 && bitwidth[2] <= 4 && bitwidth[3] <= 4 &&
bitwidth[4] <= 4 && bitwidth[5] <= 4 && bitwidth[6] <= 4)
{
#if ENCODE_DEBUG
ms_log (0, " W%02d: 11,10=7x4b %d %d %d %d %d %d %d\n",
widx, diffs[0], diffs[1], diffs[2], diffs[3], diffs[4], diffs[5], diffs[6]);
#endif
/* Mask the values, shift to proper location and set in word */
frameptr[widx] = ((uint32_t)diffs[6] & 0xFul);
frameptr[widx] |= ((uint32_t)diffs[5] & 0xFul) << 4;
frameptr[widx] |= ((uint32_t)diffs[4] & 0xFul) << 8;
frameptr[widx] |= ((uint32_t)diffs[3] & 0xFul) << 12;
frameptr[widx] |= ((uint32_t)diffs[2] & 0xFul) << 16;
frameptr[widx] |= ((uint32_t)diffs[1] & 0xFul) << 20;
frameptr[widx] |= ((uint32_t)diffs[0] & 0xFul) << 24;
/* 2-bit decode nibble is 0b10 (0x2) */
frameptr[widx] |= 0x2ul << 30;
/* 2-bit nibble is 0b11 (0x3) */
frameptr[0] |= 0x3ul << (30 - 2 * widx);
packedsamples = 7;
}
/* 6 x 5-bit differences */
else if (diffcount >= 6 &&
bitwidth[0] <= 5 && bitwidth[1] <= 5 && bitwidth[2] <= 5 &&
bitwidth[3] <= 5 && bitwidth[4] <= 5 && bitwidth[5] <= 5)
{
#if ENCODE_DEBUG
ms_log (0, " W%02d: 11,01=6x5b %d %d %d %d %d %d\n",
widx, diffs[0], diffs[1], diffs[2], diffs[3], diffs[4], diffs[5]);
#endif
/* Mask the values, shift to proper location and set in word */
frameptr[widx] = ((uint32_t)diffs[5] & 0x1Ful);
frameptr[widx] |= ((uint32_t)diffs[4] & 0x1Ful) << 5;
frameptr[widx] |= ((uint32_t)diffs[3] & 0x1Ful) << 10;
frameptr[widx] |= ((uint32_t)diffs[2] & 0x1Ful) << 15;
frameptr[widx] |= ((uint32_t)diffs[1] & 0x1Ful) << 20;
frameptr[widx] |= ((uint32_t)diffs[0] & 0x1Ful) << 25;
/* 2-bit decode nibble is 0b01 (0x1) */
frameptr[widx] |= 0x1ul << 30;
/* 2-bit nibble is 0b11 (0x3) */
frameptr[0] |= 0x3ul << (30 - 2 * widx);
packedsamples = 6;
}
/* 5 x 6-bit differences */
else if (diffcount >= 5 &&
bitwidth[0] <= 6 && bitwidth[1] <= 6 && bitwidth[2] <= 6 &&
bitwidth[3] <= 6 && bitwidth[4] <= 6)
{
#if ENCODE_DEBUG
ms_log (0, " W%02d: 11,00=5x6b %d %d %d %d %d\n",
widx, diffs[0], diffs[1], diffs[2], diffs[3], diffs[4]);
#endif
/* Mask the values, shift to proper location and set in word */
frameptr[widx] = ((uint32_t)diffs[4] & 0x3Ful);
frameptr[widx] |= ((uint32_t)diffs[3] & 0x3Ful) << 6;
frameptr[widx] |= ((uint32_t)diffs[2] & 0x3Ful) << 12;
frameptr[widx] |= ((uint32_t)diffs[1] & 0x3Ful) << 18;
frameptr[widx] |= ((uint32_t)diffs[0] & 0x3Ful) << 24;
/* 2-bit decode nibble is 0b00, nothing to set */
/* 2-bit nibble is 0b11 (0x3) */
frameptr[0] |= 0x3ul << (30 - 2 * widx);
packedsamples = 5;
}
/* 4 x 8-bit differences */
else if (diffcount >= 4 &&
bitwidth[0] <= 8 && bitwidth[1] <= 8 &&
bitwidth[2] <= 8 && bitwidth[3] <= 8)
{
#if ENCODE_DEBUG
ms_log (0, " W%02d: 01=4x8b %d %d %d %d\n",
widx, diffs[0], diffs[1], diffs[2], diffs[3]);
#endif
word = (union dword *)&frameptr[widx];
word->d8[0] = diffs[0];
word->d8[1] = diffs[1];
word->d8[2] = diffs[2];
word->d8[3] = diffs[3];
/* 2-bit nibble is 0b01, only need to set 2nd bit */
frameptr[0] |= 0x1ul << (30 - 2 * widx);
packedsamples = 4;
}
/* 3 x 10-bit differences */
else if (diffcount >= 3 &&
bitwidth[0] <= 10 && bitwidth[1] <= 10 && bitwidth[2] <= 10)
{
#if ENCODE_DEBUG
ms_log (0, " W%02d: 10,11=3x10b %d %d %d\n",
widx, diffs[0], diffs[1], diffs[2]);
#endif
/* Mask the values, shift to proper location and set in word */
frameptr[widx] = ((uint32_t)diffs[2] & 0x3FFul);
frameptr[widx] |= ((uint32_t)diffs[1] & 0x3FFul) << 10;
frameptr[widx] |= ((uint32_t)diffs[0] & 0x3FFul) << 20;
/* 2-bit decode nibble is 0b11 (0x3) */
frameptr[widx] |= 0x3ul << 30;
/* 2-bit nibble is 0b10 (0x2) */
frameptr[0] |= 0x2ul << (30 - 2 * widx);
packedsamples = 3;
}
/* 2 x 15-bit differences */
else if (diffcount >= 2 &&
bitwidth[0] <= 15 && bitwidth[1] <= 15)
{
#if ENCODE_DEBUG
ms_log (0, " W%02d: 10,10=2x15b %d %d\n",
widx, diffs[0], diffs[1]);
#endif
/* Mask the values, shift to proper location and set in word */
frameptr[widx] = ((uint32_t)diffs[1] & 0x7FFFul);
frameptr[widx] |= ((uint32_t)diffs[0] & 0x7FFFul) << 15;
/* 2-bit decode nibble is 0b10 (0x2) */
frameptr[widx] |= 0x2ul << 30;
/* 2-bit nibble is 0b10 (0x2) */
frameptr[0] |= 0x2ul << (30 - 2 * widx);
packedsamples = 2;
}
/* 1 x 30-bit difference */
else if (diffcount >= 1 &&
bitwidth[0] <= 30)
{
#if ENCODE_DEBUG
ms_log (0, " W%02d: 10,01=1x30b %d\n",
widx, diffs[0]);
#endif
/* Mask the value and set in word */
frameptr[widx] = ((uint32_t)diffs[0] & 0x3FFFFFFFul);
/* 2-bit decode nibble is 0b01 (0x1) */
frameptr[widx] |= 0x1ul << 30;
/* 2-bit nibble is 0b10 (0x2) */
frameptr[0] |= 0x2ul << (30 - 2 * widx);
packedsamples = 1;
}
else
{
ms_log (2, "%s: Unable to represent difference in <= 30 bits\n", sid);
return -1;
}
/* Swap encoded word except for 4x8-bit samples */
if (swapflag && packedsamples != 4)
ms_gswap4 (&frameptr[widx]);
diffcount -= packedsamples;
outputsamples += packedsamples;
} /* Done with words in frame */
/* Swap word with nibbles */
if (swapflag)
ms_gswap4 (&frameptr[0]);
} /* Done with frames */
/* Set Xn (reverse integration constant) in first frame to last sample */
if (Xnp)
*Xnp = *(input + outputsamples - 1);
if (swapflag)
ms_gswap4 (Xnp);
if (byteswritten)
*byteswritten = frameidx * 64;
return outputsamples;
} /* End of msr_encode_steim2() */

@ -0,0 +1,58 @@
/***************************************************************************
* Interface declarations for the miniSEED packing routines in
* packdata.c
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#ifndef PACKDATA_H
#define PACKDATA_H 1
#ifdef __cplusplus
extern "C" {
#endif
#include "libmseed.h"
#define STEIM1_FRAME_MAX_SAMPLES 60
#define STEIM2_FRAME_MAX_SAMPLES 105
/* Control for printing debugging information, declared in packdata.c */
extern int libmseed_encodedebug;
extern int msr_encode_text (char *input, int samplecount, char *output,
int outputlength);
extern int msr_encode_int16 (int32_t *input, int samplecount, int16_t *output,
int outputlength, int swapflag);
extern int msr_encode_int32 (int32_t *input, int samplecount, int32_t *output,
int outputlength, int swapflag);
extern int msr_encode_float32 (float *input, int samplecount, float *output,
int outputlength, int swapflag);
extern int msr_encode_float64 (double *input, int samplecount, double *output,
int outputlength, int swapflag);
extern int msr_encode_steim1 (int32_t *input, int samplecount, int32_t *output,
int outputlength, int32_t diff0, uint16_t *byteswritten,
int swapflag);
extern int msr_encode_steim2 (int32_t *input, int samplecount, int32_t *output,
int outputlength, int32_t diff0, uint16_t *byteswritten,
const char *sid, int swapflag);
#ifdef __cplusplus
}
#endif
#endif

File diff suppressed because it is too large Load Diff

@ -0,0 +1,927 @@
/***************************************************************************
* Generic routines to manage selection lists.
*
* This file is part of the miniSEED Library.
*
* Copyright (c) 2023 Chad Trabant, EarthScope Data Services
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
***************************************************************************/
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "libmseed.h"
static int ms_isinteger (const char *string);
static int ms_globmatch (const char *string, const char *pattern);
/**********************************************************************/ /**
* @brief Test the specified parameters for a matching selection entry
*
* Search the ::MS3Selections for an entry matching the provided
* parameters. The ::MS3Selections.sidpattern may contain globbing
* characters. The ::MS3Selections.timewindows many contain start and
* end times set to ::NSTUNSET to denote "open" times.
*
* Positive matching requires:
* @parblock
* -# glob match of sid against sidpattern in selection
* -# time window intersection with range in selection
* -# equal pubversion if selection pubversion > 0
* @endparblock
*
* @param[in] selections ::MS3Selections to search
* @param[in] sid Source ID to match
* @param[in] starttime Start time to match
* @param[in] endtime End time to match
* @param[in] pubversion Publication version to match
* @param[out] ppselecttime Pointer-to-pointer to return the matching ::MS3SelectTime entry
*
* @returns A pointer to matching ::MS3Selections entry successful
* match and NULL for no match or error.
***************************************************************************/
const MS3Selections *
ms3_matchselect (const MS3Selections *selections, const char *sid, nstime_t starttime,
nstime_t endtime, int pubversion, const MS3SelectTime **ppselecttime)
{
const MS3Selections *findsl = NULL;
const MS3SelectTime *findst = NULL;
const MS3SelectTime *matchst = NULL;
if (selections)
{
findsl = selections;
while (findsl)
{
if (ms_globmatch (sid, findsl->sidpattern))
{
if (findsl->pubversion > 0 && findsl->pubversion != pubversion)
{
findsl = findsl->next;
continue;
}
/* If no time selection, this is a match */
if (!findsl->timewindows)
{
if (ppselecttime)
*ppselecttime = NULL;
return findsl;
}
/* Otherwise, search the time selections */
findst = findsl->timewindows;
while (findst)
{
if (starttime != NSTERROR && starttime != NSTUNSET &&
findst->starttime != NSTERROR && findst->starttime != NSTUNSET &&
(starttime < findst->starttime && !(starttime <= findst->starttime && endtime >= findst->starttime)))
{
findst = findst->next;
continue;
}
else if (endtime != NSTERROR && endtime != NSTUNSET &&
findst->endtime != NSTERROR && findst->endtime != NSTUNSET &&
(endtime > findst->endtime && !(starttime <= findst->endtime && endtime >= findst->endtime)))
{
findst = findst->next;
continue;
}
matchst = findst;
break;
}
}
if (matchst)
break;
else
findsl = findsl->next;
}
}
if (ppselecttime)
*ppselecttime = matchst;
return (matchst) ? findsl : NULL;
} /* End of ms3_matchselect() */
/**********************************************************************/ /**
* @brief Test the ::MS3Record for a matching selection entry
*
* Search the ::MS3Selections for an entry matching the provided
* parameters.
*
* Positive matching requires:
* @parblock
* -# glob match of sid against sidpattern in selection
* -# time window intersection with range in selection
* -# equal pubversion if selection pubversion > 0
* @endparblock
*
* @param[in] selections ::MS3Selections to search
* @param[in] msr ::MS3Record to match against selections
* @param[out] ppselecttime Pointer-to-pointer to return the matching ::MS3SelectTime entry
*
* @returns A pointer to matching ::MS3Selections entry successful
* match and NULL for no match or error.
***************************************************************************/
const MS3Selections *
msr3_matchselect (const MS3Selections *selections, const MS3Record *msr,
const MS3SelectTime **ppselecttime)
{
nstime_t endtime;
if (!selections || !msr)
return NULL;
endtime = msr3_endtime (msr);
return ms3_matchselect (selections, msr->sid, msr->starttime, endtime,
msr->pubversion, ppselecttime);
} /* End of msr3_matchselect() */
/**********************************************************************/ /**
* @brief Add selection parameters to selection list.
*
* The \a sidpattern may contain globbing characters.
*
* The \a starttime and \a endtime may be set to ::NSTUNSET to denote
* "open" times.
*
* The \a pubversion may be set to 0 to match any publication
* version.
*
* @param[in] ppselections ::MS3Selections to add new selection to
* @param[in] sidpattern Source ID pattern, may contain globbing characters
* @param[in] starttime Start time for selection, ::NSTUNSET for open
* @param[in] endtime End time for selection, ::NSTUNSET for open
* @param[in] pubversion Publication version for selection, 0 for any
*
* @returns 0 on success and -1 on error.
*
* \ref MessageOnError - this function logs a message on error
***************************************************************************/
int
ms3_addselect (MS3Selections **ppselections, const char *sidpattern,
nstime_t starttime, nstime_t endtime, uint8_t pubversion)
{
MS3Selections *newsl = NULL;
MS3SelectTime *newst = NULL;
if (!ppselections || !sidpattern)
{
ms_log (2, "Required argument not defined: 'ppselections' or 'sidpattern'\n");
return -1;
}
/* Allocate new SelectTime and populate */
if (!(newst = (MS3SelectTime *)libmseed_memory.malloc (sizeof (MS3SelectTime))))
{
ms_log (2, "Cannot allocate memory\n");
return -1;
}
memset (newst, 0, sizeof (MS3SelectTime));
newst->starttime = starttime;
newst->endtime = endtime;
/* Add new Selections struct to begining of list */
if (!*ppselections)
{
/* Allocate new Selections and populate */
if (!(newsl = (MS3Selections *)libmseed_memory.malloc (sizeof (MS3Selections))))
{
ms_log (2, "Cannot allocate memory\n");
return -1;
}
memset (newsl, 0, sizeof (MS3Selections));
strncpy (newsl->sidpattern, sidpattern, sizeof (newsl->sidpattern));
newsl->sidpattern[sizeof (newsl->sidpattern) - 1] = '\0';
newsl->pubversion = pubversion;
/* Add new MS3SelectTime struct as first in list */
*ppselections = newsl;
newsl->timewindows = newst;
}
else
{
MS3Selections *findsl = *ppselections;
MS3Selections *matchsl = 0;
/* Search for matching MS3Selections entry */
while (findsl)
{
if (!strcmp (findsl->sidpattern, sidpattern) && findsl->pubversion == pubversion)
{
matchsl = findsl;
break;
}
findsl = findsl->next;
}
if (matchsl)
{
/* Add time window selection to beginning of window list */
newst->next = matchsl->timewindows;
matchsl->timewindows = newst;
}
else
{
/* Allocate new MS3Selections and populate */
if (!(newsl = (MS3Selections *)libmseed_memory.malloc (sizeof (MS3Selections))))
{
ms_log (2, "Cannot allocate memory\n");
return -1;
}
memset (newsl, 0, sizeof (MS3Selections));
strncpy (newsl->sidpattern, sidpattern, sizeof (newsl->sidpattern));
newsl->sidpattern[sizeof (newsl->sidpattern) - 1] = '\0';
newsl->pubversion = pubversion;
/* Add new MS3Selections to beginning of list */
newsl->next = *ppselections;
*ppselections = newsl;
newsl->timewindows = newst;
}
}
return 0;
} /* End of ms3_addselect() */
/**********************************************************************/ /**
* @brief Add selection parameters to a selection list based on
* separate source name codes
*
* The \a network, \a station, \a location, and \a channel arguments may
* contain globbing parameters.
* The \a starttime and \a endtime may be set to ::NSTUNSET to denote
* "open" times.
*
* The \a pubversion may be set to 0 to match any publication
* version.
*
* If any of the naming parameters are not supplied (pointer is NULL)
* a wildcard for all matches is substituted.
*
* As a special case, if the location code (loc) is set to \c "--" to
* match an empty location code it will be translated to an empty string
* to match libmseed's notation.
*
* @param[in] ppselections ::MS3Selections to add new selection to
* @param[in] network Network code, may contain globbing characters
* @param[in] station Statoin code, may contain globbing characters
* @param[in] location Location code, may contain globbing characters
* @param[in] channel channel code, may contain globbing characters
* @param[in] starttime Start time for selection, ::NSTUNSET for open
* @param[in] endtime End time for selection, ::NSTUNSET for open
* @param[in] pubversion Publication version for selection, 0 for any
*
* @return 0 on success and -1 on error.
*
* \ref MessageOnError - this function logs a message on error
***************************************************************************/
int
ms3_addselect_comp (MS3Selections **ppselections, char *network, char *station,
char *location, char *channel, nstime_t starttime,
nstime_t endtime, uint8_t pubversion)
{
char sidpattern[100];
char selnet[20];
char selsta[20];
char selloc[20];
char selchan[20];
if (!ppselections)
{
ms_log (2, "Required argument not defined: 'ppselections'\n");
return -1;
}
if (network)
{
strncpy (selnet, network, sizeof (selnet));
selnet[sizeof (selnet) - 1] = '\0';
}
else
{
strcpy (selnet, "*");
}
if (station)
{
strncpy (selsta, station, sizeof (selsta));
selsta[sizeof (selsta) - 1] = '\0';
}
else
{
strcpy (selsta, "*");
}
if (location)
{
/* Test for special case blank location ID */
if (!strcmp (location, "--"))
{
selloc[0] = '\0';
}
else
{
strncpy (selloc, location, sizeof (selloc));
selloc[sizeof (selloc) - 1] = '\0';
}
}
else
{
strcpy (selloc, "*");
}
if (channel)
{
/* Convert a 3-character SEED 2.x channel code to an extended code */
if (ms_globmatch (channel, "[?*a-zA-Z0-9][?*a-zA-Z0-9][?*a-zA-Z0-9]"))
{
ms_seedchan2xchan (selchan, channel);
}
else
{
strncpy (selchan, channel, sizeof (selchan));
selchan[sizeof (selchan) - 1] = '\0';
}
}
else
{
strcpy (selchan, "*");
}
/* Create the source identifier globbing match for this entry */
if (ms_nslc2sid (sidpattern, sizeof (sidpattern), 0,
selnet, selsta, selloc, selchan) < 0)
return -1;
/* Add selection to list */
if (ms3_addselect (ppselections, sidpattern, starttime, endtime, pubversion))
return -1;
return 0;
} /* End of ms3_addselect_comp() */
#define MAX_SELECTION_FIELDS 8
/**********************************************************************/ /**
* @brief Read data selections from a file
*
* Selections from a file are added to the specified selections list.
* On errors this routine will leave allocated memory unreachable
* (leaked), it is expected that this is a program failing condition.
*
* As a special case if the filename is "-", selection lines will be
* read from stdin.
*
* Each line of the file contains a single selection and may be one of
* these two line formats:
* @code
* SourceID [Starttime [Endtime [Pubversion]]]
* @endcode
* or
* @code
* Network Station Location Channel [Pubversion [Starttime [Endtime]]]
* @endcode
*
* The \c Starttime and \c Endtime values must be in a form recognized
* by ms_timestr2nstime() and include a full date (i.e. just a year is
* not allowed).
*
* In the latter version, if the "Channel" field is a SEED 2.x channel
* (3-characters) it will automatically be converted into extended
* channel form (band_source_subsource).
*
* In the latter version, the "Pubversion" field, which was "Quality"
* in earlier versions of the library, is assumed to be a publication
* version if it is an integer, otherwise it is ignored.
*
* @returns Count of selections added on success and -1 on error.
*
* \ref MessageOnError - this function logs a message on error
***************************************************************************/
int
ms3_readselectionsfile (MS3Selections **ppselections, const char *filename)
{
FILE *fp;
nstime_t starttime;
nstime_t endtime;
uint8_t pubversion;
char selectline[200];
char *line;
char *fields[MAX_SELECTION_FIELDS];
char *cp;
char next;
int selectcount = 0;
int linecount = 0;
int fieldidx;
uint8_t isstart2;
uint8_t isend3;
uint8_t isstart6;
uint8_t isend7;
if (!ppselections || !filename)
{
ms_log (2, "Required argument not defined: 'ppselections' or 'filename'\n");
return -1;
}
if (strcmp (filename, "-"))
{
if (!(fp = fopen (filename, "rb")))
{
ms_log (2, "Cannot open file %s: %s\n", filename, strerror (errno));
return -1;
}
}
else
{
/* Use stdin as special case */
fp = stdin;
}
while (fgets (selectline, sizeof (selectline) - 1, fp))
{
linecount++;
/* Reset fields array */
for (fieldidx = 0; fieldidx < MAX_SELECTION_FIELDS; fieldidx++)
fields[fieldidx] = NULL;
/* Guarantee termination */
selectline[sizeof (selectline) - 1] = '\0';
line = selectline;
/* Trim trailing whitespace (including newlines, carriage returns, etc.) if any */
cp = line;
while (*cp != '\0')
{
cp++;
}
cp--;
while (cp >= line && isspace((int)(*cp)))
{
*cp = '\0';
cp--;
}
/* Trim leading whitespace if any */
cp = line;
while (isspace((int)(*cp)))
{
line = cp = cp+1;
}
/* Skip empty lines */
if (!strlen (line))
continue;
/* Skip comment lines */
if (*line == '#')
continue;
/* Set fields array to whitespace delimited fields */
cp = line;
next = 0; /* For this loop: 0 = whitespace, 1 = non-whitespace */
fieldidx = 0;
while (*cp && fieldidx < MAX_SELECTION_FIELDS)
{
if (!isspace ((int)(*cp)))
{
/* Field starts at transition from whitespace to non-whitespace */
if (next == 0)
{
fields[fieldidx] = cp;
fieldidx++;
}
next = 1;
}
else
{
/* Field ends at transition from non-whitespace to whitespace */
if (next == 1)
*cp = '\0';
next = 0;
}
cp++;
}
/* Globbing pattern to match the beginning of a date "YYYY[-/,]#..." */
#define INITDATEGLOB "[0-9][0-9][0-9][0-9][-/,][0-9]*"
isstart2 = (fields[1]) ? ms_globmatch (fields[1], INITDATEGLOB) : 0;
isend3 = (fields[2]) ? ms_globmatch (fields[2], INITDATEGLOB) : 0;
isstart6 = (fields[5]) ? ms_globmatch (fields[5], INITDATEGLOB) : 0;
isend7 = (fields[6]) ? ms_globmatch (fields[6], INITDATEGLOB) : 0;
/* Convert starttime to nstime_t */
starttime = NSTUNSET;
cp = NULL;
if (isstart2)
cp = fields[1];
else if (isstart6)
cp = fields[5];
if (cp)
{
starttime = ms_timestr2nstime (cp);
if (starttime == NSTUNSET)
{
ms_log (2, "Cannot convert data selection start time (line %d): %s\n", linecount, cp);
return -1;
}
}
/* Convert endtime to nstime_t */
endtime = NSTUNSET;
cp = NULL;
if (isend3)
cp = fields[2];
else if (isend7)
cp = fields[6];
if (cp)
{
endtime = ms_timestr2nstime (cp);
if (endtime == NSTUNSET)
{
ms_log (2, "Cannot convert data selection end time (line %d): %s\n", linecount, cp);
return -1;
}
}
/* Test for "SourceID [Starttime [Endtime [Pubversion]]]" */
if (fieldidx == 1 ||
(fieldidx == 2 && isstart2) ||
(fieldidx == 3 && isstart2 && isend3) ||
(fieldidx == 4 && isstart2 && isend3 && ms_isinteger(fields[3])))
{
/* Convert publication version to integer */
pubversion = 0;
if (fields[3])
{
long int longpver;
longpver = strtol (fields[3], NULL, 10);
if (longpver < 0 || longpver > 255 )
{
ms_log (2, "Cannot convert publication version (line %d): %s\n", linecount, fields[3]);
return -1;
}
else
{
pubversion = (uint8_t) longpver;
}
}
/* Add selection to list */
if (ms3_addselect (ppselections, fields[0], starttime, endtime, pubversion))
{
ms_log (2, "%s: Error adding selection on line %d\n", filename, linecount);
return -1;
}
}
/* Test for "Network Station Location Channel [Quality [Starttime [Endtime]]]" */
else if (fieldidx == 4 || fieldidx == 5 ||
(fieldidx == 6 && isstart6) ||
(fieldidx == 7 && isstart6 && isend7))
{
/* Convert quality field to publication version if integer */
pubversion = 0;
if (fields[4] && ms_isinteger(fields[4]))
{
long int longpver;
longpver = strtol (fields[4], NULL, 10);
if (longpver < 0 || longpver > 255 )
{
ms_log (2, "Cannot convert publication version (line %d): %s\n", linecount, fields[4]);
return -1;
}
else
{
pubversion = (uint8_t) longpver;
}
}
if (ms3_addselect_comp (ppselections, fields[0], fields[1], fields[2], fields[3],
starttime, endtime, pubversion))
{
ms_log (2, "%s: Error adding selection on line %d\n", filename, linecount);
return -1;
}
}
else
{
ms_log (1, "%s: Skipping unrecognized data selection on line %d\n", filename, linecount);
}
selectcount++;
}
if (fp != stdin)
fclose (fp);
return selectcount;
} /* End of ms_readselectionsfile() */
/**********************************************************************/ /**
* @brief Free all memory associated with a ::MS3Selections
*
* All memory from one or more ::MS3Selections (in a linked list) are freed.
*
* @param[in] selections Start of ::MS3Selections to free
***************************************************************************/
void
ms3_freeselections (MS3Selections *selections)
{
MS3Selections *select;
MS3Selections *selectnext;
MS3SelectTime *selecttime;
MS3SelectTime *selecttimenext;
if (selections)
{
select = selections;
while (select)
{
selectnext = select->next;
selecttime = select->timewindows;
while (selecttime)
{
selecttimenext = selecttime->next;
libmseed_memory.free (selecttime);
selecttime = selecttimenext;
}
libmseed_memory.free (select);
select = selectnext;
}
}
} /* End of ms3_freeselections() */
/**********************************************************************/ /**
* @brief Print the selections list using the ms_log() facility.
*
* All selections are printed with simple formatting.
*
* @param[in] selections Start of ::MS3Selections to print
***************************************************************************/
void
ms3_printselections (const MS3Selections *selections)
{
const MS3Selections *select;
MS3SelectTime *selecttime;
char starttime[50];
char endtime[50];
if (!selections)
return;
select = selections;
while (select)
{
ms_log (0, "Selection: %s pubversion: %d\n",
select->sidpattern, select->pubversion);
selecttime = select->timewindows;
while (selecttime)
{
if (selecttime->starttime != NSTERROR && selecttime->starttime != NSTUNSET)
ms_nstime2timestr (selecttime->starttime, starttime, ISOMONTHDAY_Z, NANO_MICRO_NONE);
else
strncpy (starttime, "No start time", sizeof (starttime) - 1);
if (selecttime->endtime != NSTERROR && selecttime->endtime != NSTUNSET)
ms_nstime2timestr (selecttime->endtime, endtime, ISOMONTHDAY_Z, NANO_MICRO_NONE);
else
strncpy (endtime, "No end time", sizeof (endtime) - 1);
ms_log (0, " %30s %30s\n", starttime, endtime);
selecttime = selecttime->next;
}
select = select->next;
}
} /* End of ms3_printselections() */
/***************************************************************************
* ms_isinteger:
*
* Test a string for all digits, i.e. and integer
*
* Returns 1 if is integer and 0 otherwise.
***************************************************************************/
static int
ms_isinteger (const char *string)
{
while (*string)
{
if (!isdigit((int)(*string)))
return 0;
string++;
}
return 1;
}
/***********************************************************************
* robust glob pattern matcher
* ozan s. yigit/dec 1994
* public domain
*
* glob patterns:
* * matches zero or more characters
* ? matches any single character
* [set] matches any character in the set
* [^set] matches any character NOT in the set
* where a set is a group of characters or ranges. a range
* is written as two characters seperated with a hyphen: a-z denotes
* all characters between a to z inclusive.
* [-set] set matches a literal hypen and any character in the set
* []set] matches a literal close bracket and any character in the set
*
* char matches itself except where char is '*' or '?' or '['
* \char matches char, including any pattern character
*
* examples:
* a*c ac abc abbc ...
* a?c acc abc aXc ...
* a[a-z]c aac abc acc ...
* a[-a-z]c a-c aac abc ...
*
* Revision 1.4 2004/12/26 12:38:00 ct
* Changed function name (amatch -> globmatch), variables and
* formatting for clarity. Also add matching header globmatch.h.
*
* Revision 1.3 1995/09/14 23:24:23 oz
* removed boring test/main code.
*
* Revision 1.2 94/12/11 10:38:15 oz
* charset code fixed. it is now robust and interprets all
* variations of charset [i think] correctly, including [z-a] etc.
*
* Revision 1.1 94/12/08 12:45:23 oz
* Initial revision
***********************************************************************/
#define GLOBMATCH_TRUE 1
#define GLOBMATCH_FALSE 0
#define GLOBMATCH_NEGATE '^' /* std char set negation char */
/***********************************************************************
* ms_globmatch:
*
* Check if a string matches a globbing pattern.
*
* Return 0 if string does not match pattern and non-zero otherwise.
**********************************************************************/
static int
ms_globmatch (const char *string, const char *pattern)
{
int negate;
int match;
int c;
while (*pattern)
{
if (!*string && *pattern != '*')
return GLOBMATCH_FALSE;
switch (c = *pattern++)
{
case '*':
while (*pattern == '*')
pattern++;
if (!*pattern)
return GLOBMATCH_TRUE;
if (*pattern != '?' && *pattern != '[' && *pattern != '\\')
while (*string && *pattern != *string)
string++;
while (*string)
{
if (ms_globmatch (string, pattern))
return GLOBMATCH_TRUE;
string++;
}
return GLOBMATCH_FALSE;
case '?':
if (*string)
break;
return GLOBMATCH_FALSE;
/* set specification is inclusive, that is [a-z] is a, z and
* everything in between. this means [z-a] may be interpreted
* as a set that contains z, a and nothing in between.
*/
case '[':
if (*pattern != GLOBMATCH_NEGATE)
negate = GLOBMATCH_FALSE;
else
{
negate = GLOBMATCH_TRUE;
pattern++;
}
match = GLOBMATCH_FALSE;
while (!match && (c = *pattern++))
{
if (!*pattern)
return GLOBMATCH_FALSE;
if (*pattern == '-') /* c-c */
{
if (!*++pattern)
return GLOBMATCH_FALSE;
if (*pattern != ']')
{
if (*string == c || *string == *pattern ||
(*string > c && *string < *pattern))
match = GLOBMATCH_TRUE;
}
else
{ /* c-] */
if (*string >= c)
match = GLOBMATCH_TRUE;
break;
}
}
else /* cc or c] */
{
if (c == *string)
match = GLOBMATCH_TRUE;
if (*pattern != ']')
{
if (*pattern == *string)
match = GLOBMATCH_TRUE;
}
else
break;
}
}
if (negate == match)
return GLOBMATCH_FALSE;
/* If there is a match, skip past the charset and continue on */
while (*pattern && *pattern != ']')
pattern++;
if (!*pattern++) /* oops! */
return GLOBMATCH_FALSE;
break;
case '\\':
if (*pattern)
c = *pattern++;
default:
if (c != *string)
return GLOBMATCH_FALSE;
break;
}
string++;
}
return !*string;
} /* End of ms_globmatch() */

@ -0,0 +1,49 @@
# This Makefile requires GNU make, sometimes available as gmake.
#
# A simple test suite for libmseed.
# See README for description.
#
# Build environment can be configured the following
# environment variables:
# CC : Specify the C compiler to use
# CFLAGS : Specify compiler options to use
# Required compiler parameters
CFLAGS += -I.. -I.
LDFLAGS += -L..
LDLIBS := -lmseed $(LDLIBS)
# Source code from example programs
EXAMPLE_SRCS := $(sort $(wildcard lm_*.c))
EXAMPLE_BINS := $(EXAMPLE_SRCS:%.c=%)
# Source code for tests
TEST_SRCS := $(sort $(wildcard test-*.c))
TEST_RUNNER := test-runner
# ASCII color coding for test results, green for PASSED and red for FAILED
PASSED := \033[0;32mPASSED\033[0m
FAILED := \033[0;31mFAILED\033[0m
test all: $(EXAMPLE_BINS) $(TEST_RUNNER) runtests
# Build example programs and check for executables
$(EXAMPLE_BINS) : % : %.c
@$(CC) $(CFLAGS) -o $@ $< $(LDFLAGS) $(LDLIBS); exit 0;
@if test -x $@; \
then printf '$(PASSED) Building $<\n'; \
else printf '$(FAILED) Building $<\n'; exit 1; \
fi
# Build tests
.PHONY: $(TEST_RUNNER)
$(TEST_RUNNER):
$(CC) $(CFLAGS) -o $@ $(TEST_SRCS) $(LDFLAGS) $(LDLIBS) -Wno-unused-but-set-variable
# Execute tests
runtests: $(TEST_RUNNER)
@./$(TEST_RUNNER)
clean:
@rm -rf $(EXAMPLE_BINS) $(TEST_RUNNER) testdata-* *.dSYM

@ -0,0 +1,22 @@
#
# Nmake file for libmseed tests - MS Visual C/C++
# Use 'nmake -f Makefile.win'
INCS = /I. /I..
LIBS = ..\libmseed.lib
OPTS = /D_CRT_SECURE_NO_WARNINGS
TEST_RUNNER = test-runner.exe
test: $(TEST_RUNNER)
$(TEST_RUNNER)
$(TEST_RUNNER): test-*.obj
link $** $(LIBS) /nologo /OUT:$@
.c.obj:
$(CC) $(CFLAGS) $(INCS) $(OPTS) /nologo /c $<
# Clean-up directives
clean:
-del a.out core *.o *.obj *% *~ $(TEST_RUNNER) testdata-*

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save