2021年10月18日16

1. 针对3288 g300g400 增加校正信息实时显示;
2.增加usb vid pid 配置;
3.增加速度模式配置功能;
This commit is contained in:
lovelyyoung 2021-10-18 16:30:13 +08:00
parent 9897512880
commit 9ec1ff241e
23 changed files with 332 additions and 83 deletions

View File

@ -13,3 +13,8 @@
2. 增加明场暗场校正最大明场值配置;
3. 界面UI按钮顺序调整对齐等操作
V4.2版本
2021年10月18日16
1. 针对3288 g300g400 增加校正信息实时显示;
2.增加usb vid pid 配置;
3.增加速度模式配置功能;

View File

@ -143,6 +143,8 @@ void CA3::OnGetOrSetSp(bool get, int type)
}
void CA3::OnGetOrSetSleepTime(bool get, int type)
{
int sp;
@ -289,18 +291,28 @@ void CA3::updatespeedmode(bool get)
if (parent != NULL)
{
if (parent->m_drv.get() && parent->m_drv->IsConnected()) {
int speedmode;
int speedmode=0;
if (get)
{
parent->m_drv->GetSpeedMode(speedmode, true);
bool bfound = false;
for (size_t i = 0; i < speedmodeMap.size(); i++)
{
if (speedmodeMap[i].Speedmode == speedmode)
if (parent->m_drv->PID == 0x0139 || parent->m_drv->PID == 0x0239)
{
m_cmbSpeedmode.SetCurSel(i);
OnGetOrSetSp(true, 0);//更新灰度sp
OnGetOrSetSp(true, 1);//更新彩色sp
if (speedmodeMap[i].Speedmode == speedmode)
{
m_cmbSpeedmode.SetCurSel(i);
OnGetOrSetSp(true, 0);//¸üлҶÈsp
OnGetOrSetSp(true, 1);//¸üвÊÉ«sp
bfound = true;
break;
}
}
else if (parent->m_drv->PID == 0x0300 || parent->m_drv->PID == 0x0400)
{
int startindex = parent->m_drv->PID == 0x0300 ? 6 : 10;
m_cmbSpeedmode.SetCurSel(startindex+ speedmode);
bfound = true;
break;
}
@ -314,9 +326,16 @@ void CA3::updatespeedmode(bool get)
if (cmbindex != -1)
{
auto t_speedmode = speedmodeMap[cmbindex];
parent->m_drv->GetSpeedMode(t_speedmode.Speedmode, false);
parent->m_drv->SetSptime(0, t_speedmode.GraySp);
parent->m_drv->SetSptime(1, t_speedmode.ColorSp);
if (parent->m_drv->PID == 0x0139 || parent->m_drv->PID == 0x0239)
{
parent->m_drv->GetSpeedMode(t_speedmode.Speedmode, false);
parent->m_drv->SetSptime(0, t_speedmode.GraySp);
parent->m_drv->SetSptime(1, t_speedmode.ColorSp);
}
else if (parent->m_drv->PID == 0x0300 || parent->m_drv->PID == 0x0400)
{
parent->m_drv->GetSpeedMode(t_speedmode.Speedmode, false);
}
}
}
}

View File

@ -51,6 +51,7 @@ private:
unsigned int ColorSp;
unsigned int GraySp;
};
std::map<int, speedmodeparam> speedmodeMap = {
{0,{70,0x42d,0xc88}},
{1,{80,0x37f,0xa7f}},
@ -58,17 +59,35 @@ private:
{3,{100,0x27c,0x775}},
{4,{110,0x27c,0x775}},
{5,{120,0x27c,0x775}},
{6,{130,0x27c,0x775}}
{6,{130,0x27c,0x775}},
{7,{1,0,0}},
{8,{2,0,0}},
{9,{3,0,0}},
{10,{4,0,0}},
{11,{1,0,0}},
{12,{2,0,0}},
{13,{3,0,0}},
{14,{4,0,0}},
{15,{5,0,0}}
};
std::map<int, CString> speedmodeMapString = {
{0,L"G100_70PPM"},
{1,L"G100_80PPM"},
{2,L"G100_90PPM"},
{3,L"G200_100PPM"},
{4,L"G200_110PPM"},
{5,L"G200_120PPM"},
{6,L"G200_130PPM"}
{0,L"G139_70PPM"},
{1,L"G139_80PPM"},
{2,L"G139_90PPM"},
{3,L"G239_100PPM"},
{4,L"G239_110PPM"},
{5,L"G239_120PPM"},
{6,L"G239_130PPM"},
{7,L"G300_40PPM"},
{8,L"G300_50PPM"},
{9,L"G300_60PPM"},
{10,L"G300_700PPM"},
{11,L"G400_40PPM"},
{12,L"G400_50PPM"},
{13,L"G400_60PPM"},
{14,L"G400_70PPM"},
{15,L"G400_80PPM"},
};
CComboBox m_cmbSpeedmode;
};

View File

@ -191,6 +191,15 @@ void CA4::OnBnClickedBtnReboot()
/// </summary>
void CA4::OnBnClickedBtnSetvidpid()
{
auto ret= MessageBox(L"设置前请务必确认校正以及速度模式等与设备相关的设置已完成避免更改VID PID后部分功能不可用确认设置吗", L"提示", MB_YESNO | MB_ICONWARNING);
if (ret == IDOK || ret == IDYES)
{
auto parent = (CHuaGoCorrectDlg*)GetParent();
if (parent->m_drv.get() && parent->m_drv->IsConnected()) {
auto vidpid = AqrVIDPID();
parent->m_drv->GetOrSetVIDPID(vidpid, false);
}
}
}
/// <summary>
@ -198,7 +207,14 @@ void CA4::OnBnClickedBtnSetvidpid()
/// </summary>
void CA4::OnBnClickedBtnGetvidpid()
{
// TODO: 在此添加控件通知处理程序代码
auto parent = (CHuaGoCorrectDlg*)GetParent();
if (parent->m_drv.get() && parent->m_drv->IsConnected()) {
int vidpid = 0;
parent->m_drv->GetOrSetVIDPID(vidpid, true);
VIDPID tvpd;
tvpd.Value = vidpid;
UpdateVidPid(tvpd);
}
}
/// <summary>
@ -428,3 +444,36 @@ void CA4::OnEnChangetbxfrexposure2()
// TODO: 在此添加控件通知处理程序代码
}
int CA4::AqrVIDPID()
{
VIDPID t_vidpid = { 0 };
CString str_vid, str_pid;
GetDlgItemText(IDC_tbxVID, str_vid);
str_vid.Replace(L"0x",L"");
USES_CONVERSION;
std::string str(W2A(str_vid));
t_vidpid.VID = strtol(str.c_str(),NULL,16);// atoi(str.c_str());
GetDlgItemText(IDC_tbxPID, str_pid);
str_pid.Replace(L"0x", L"");
std::string cstr_pid(W2A(str_pid));
t_vidpid.PID = strtol(cstr_pid.c_str(), NULL, 16);// atoi(cstr_pid.c_str());
return t_vidpid.Value;
}
void CA4::UpdateVidPid(VIDPID vidpid)
{
if (vidpid.PID != 0 && vidpid.VID != 0)
{
CString str_vid, str_pid;
str_vid.Format(L"0x%x", vidpid.VID);
str_pid.Format(L"0x%x", vidpid.PID);
GetDlgItem(IDC_tbxVID)->SetWindowText(str_vid);
GetDlgItem(IDC_tbxPID)->SetWindowText(str_pid);
}
else
{
MessageBox(L"错误的VID PID", L"提示", MB_OK);
}
}

View File

@ -8,6 +8,7 @@
#include "JsonConfig.h"
#include <functional>
// CA4 对话框
#define INI_FILE_NAME "./HuaGoScan.ini"
class CA4 : public CDialog
@ -22,7 +23,15 @@ public:
// 对话框数据
enum { IDD = IDD_A4_DIALOG };
union VIDPID
{
struct
{
unsigned short VID;
unsigned short PID;
};
unsigned int Value;
};
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
@ -75,4 +84,6 @@ public:
afx_msg void OnBnClickedBtnbdown();
void UpdateGains(int id, bool get);
afx_msg void OnEnChangetbxfrexposure2();
int AqrVIDPID();
void UpdateVidPid(VIDPID vidpid);
};

Binary file not shown.

Binary file not shown.

View File

@ -240,6 +240,7 @@ opencv_imgproc2410.lib;%(AdditionalDependencies)</AdditionalDependencies>
<ClInclude Include="stdafx.h" />
<ClInclude Include="targetver.h" />
<ClInclude Include="ThreadPool.h" />
<ClInclude Include="vendorconfig.h" />
</ItemGroup>
<ItemGroup>
<ClCompile Include="A3.cpp" />
@ -263,6 +264,7 @@ opencv_imgproc2410.lib;%(AdditionalDependencies)</AdditionalDependencies>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
</ClCompile>
<ClCompile Include="vendorconfig.cpp" />
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="HuaGoCorrect.rc" />

View File

@ -120,6 +120,9 @@
<ClInclude Include="ThreadPool.h">
<Filter>头文件</Filter>
</ClInclude>
<ClInclude Include="vendorconfig.h">
<Filter>头文件</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ClCompile Include="HuaGoCorrect.cpp">
@ -170,6 +173,9 @@
<ClCompile Include="gscan3399.cpp">
<Filter>源文件\USB通信</Filter>
</ClCompile>
<ClCompile Include="vendorconfig.cpp">
<Filter>源文件</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="HuaGoCorrect.rc">

View File

@ -340,13 +340,27 @@ void CHuaGoCorrectDlg::RefreshTabChange()
void CHuaGoCorrectDlg::Scan()
{
HGScanConfig config = { 0 };
config.g200params.dpi = 1;//only support 200DPI
config.g200params.paper = 0;
config.g200params.pc_correct = ((CButton*)GetDlgItem(IDC_CKBORGINIMG))->GetCheck();
config.g200params.color = m_iColorIndex == 1 ? 1 : 0;
config.g200params.double_feed_enbale = TRUE;
config.g200params.screw_detect_enable = FALSE;
config.g200params.iscorrect_mode = 1;//УÕýģʽ
if (m_drv->PID == 0x0139 || m_drv->PID == 0x0239)
{
config.g200params.dpi = 1;//only support 200DPI
config.g200params.paper = 0;
config.g200params.pc_correct = ((CButton*)GetDlgItem(IDC_CKBORGINIMG))->GetCheck();
config.g200params.color = m_iColorIndex == 1 ? 1 : 0;
config.g200params.double_feed_enbale = TRUE;
config.g200params.screw_detect_enable = FALSE;
config.g200params.iscorrect_mode = 1;//УÕýģʽ
}
else
{
config.g400params.dpi = 1;//only support 200DPI
config.g400params.pageSize = 0;
config.g400params.isCorrect = !((CButton*)GetDlgItem(IDC_CKBORGINIMG))->GetCheck();
config.g400params.isColor = m_iColorIndex == 1 ? 1 : 0;
config.g400params.doubleFeeded = TRUE;
config.g400params.enableStable = FALSE;
config.g400params.reversed1 = 0;//УÕýģʽ
}
m_drv->Config_Scanner(config);
this_thread::sleep_for(std::chrono::milliseconds(1000));
@ -409,6 +423,7 @@ void CHuaGoCorrectDlg::OnBnClickedBtnFlat()
std::string c_str = StringToUtf(info);
CString pWideChar = A2T(c_str.c_str());
CString oldinfo;
UpdateData(FALSE);
((CEdit*)(m_A3dlg.GetDlgItem(IDC_LSTFLATINFO)))->GetWindowText(oldinfo);
oldinfo += pWideChar;
((CEdit*)(m_A3dlg.GetDlgItem(IDC_LSTFLATINFO)))->SetWindowText(oldinfo);

View File

@ -51,6 +51,7 @@ public:
virtual bool Updata(std::string filename, std::function<void(long, long)> func) = 0;
virtual void SetFlatCallback(std::function<void(std::string)> func) = 0;
virtual void GetSpeedMode(int& speedmode,bool get) = 0 ;
virtual void GetOrSetVIDPID(int& value, bool get) = 0;
void SetPath(std::string csFilePath)
{
csPath = csFilePath;
@ -65,4 +66,6 @@ public:
ImageMatQueue m_pImages;
HWND h;
std::string csPath;
unsigned short VID;
unsigned short PID;
};

View File

@ -111,10 +111,13 @@ void ImageMatQueue::proc()
{
if (pixType != -1)
{
std::string csName;
SYSTEMTIME st = { 0 };
GetLocalTime(&st); //获取当前时间 可精确到ms
//csName.Format("%02d%02d%02d-%d.bmp", st.wHour, st.wMinute, st.wSecond,++imgindex);
time_t timp;
tm* p;
time(&timp);
p = localtime(&timp);
std::string csName = std::to_string(p->tm_hour) + "_" + std::to_string(p->tm_min) + "_" + std::to_string(p->tm_sec)+".png";
cv::Mat matPicImage;
cv::Mat matFront, matBack;
@ -126,8 +129,8 @@ void ImageMatQueue::proc()
{
if (m_pImages.Size() >= 2)
{
matFront = m_pImages.Take().getMat(pixType);
matBack = m_pImages.Take().getMat(pixType);
matFront = m_pImages.Take().getMat(pixType==1 ? 1 : 6);//bgr or gray
matBack = m_pImages.Take().getMat(pixType == 1 ? 1 : 6);
//mats.push_back(matFront);
//mats.push_back(matBack);
}
@ -138,13 +141,9 @@ void ImageMatQueue::proc()
case 4://G500 正反面图像在一副图上,需要均分图像
{
std::string csImage;
csImage = csPath + "\\G300" + csName;
//cv::Mat mat = m_pImages.Take().getMat(pixType);
//matPicImage = mat(cv::Rect(0, 0, mat.cols, mat.rows));
////mats.push_back(matPicImage);
//IplImage qqImg;
//qqImg = IplImage(matPicImage); // cv::Mat -> IplImage
//cvSaveImage(csImage, &qqImg);
csImage = csPath+"//" + csName;
cv::Mat mat = m_pImages.Take().getMat(pixType == 1 ? 1 : 6);
cv::imwrite(csImage, mat);
m_images.Put(csImage);
}
break;

View File

@ -48,7 +48,7 @@ cv::Mat JpegBuffer::getMat( int pixType)
StopWatch sw;
//XdPrint("buffer size is :%d ==========================\n",getSize());
cv::Mat image = jl.decode(m_buffer, pixType);//oixtype
cv::imwrite("img.jpg", image);
XdPrint(L"Decode Image time epleased :%lf ==========================\n",sw.elapsed_ms());
//XdPrint("==image col is :%d, image row is :%d, image size is :%d===\n",image.cols, image.rows, image.size);

View File

@ -228,6 +228,8 @@ enum tagUsbSupported
V4L2_AQULRE_ERROR = 79,
//扫描仪内部图片丢失
V4L2_IMAGE_EMPTY = 80,
//自动校正中
AUTO_FLATTING = 198,
//USB 未连接
USB_DISCONNECTED = 200,
//用户点击停止

View File

@ -60,6 +60,8 @@ void gscan3399::open(int vid, int pid, int index)
if (!usbs.empty())
{
m_usb = *usbs.begin();
VID = vid;
PID = pid;
m_usb->open();
if (m_usb->is_connected())
{
@ -484,6 +486,11 @@ void gscan3399::GetSpeedMode(int& speedmode, bool get)
}
}
void gscan3399::GetOrSetVIDPID(int& value, bool get)
{
}
void gscan3399::usbcallback(bool isleft, void* usrdata)
{
gscan3399* This = (gscan3399*)usrdata;

View File

@ -69,7 +69,7 @@ public:
virtual void SetFlatCallback(std::function<void(std::string)> func);
virtual void GetSpeedMode(int& speedmode,bool getorset);
virtual void GetOrSetVIDPID(int& value, bool get) override;
private:
static void usbcallback(bool isleft, void* usrdata);

View File

@ -80,6 +80,8 @@ void GScn_Drv::open(int vid, int pid,int index)
{
m_usb = *devs.begin();
m_usb->open();//同时存在多个同种扫描设备时默认选取第一个vid pid匹配的设备
VID = vid;
PID = pid;
selectDeviceIndex=index;
m_scannerType=G300;
h= ::FindWindow(NULL, L"HGScannerTool");
@ -238,6 +240,30 @@ void GScn_Drv::SetFlatCallback(std::function<void(std::string)> func)
void GScn_Drv::GetSpeedMode(int& speedmode, bool get)
{
if (m_usb.get() && m_usb->is_connected())
{
USBCB speed = { get ? GET_SPEED_MODE:SET_SPEED_MODE,speedmode,0 };
m_usb->write_bulk(&speed, sizeof(speed));
if (get)
{
m_usb->read_bulk(&speed, sizeof(speed));
speedmode = speed.u32_Data;
}
}
}
void GScn_Drv::GetOrSetVIDPID(int& value, bool get)
{
if (m_usb.get() && m_usb->is_connected())
{
USBCB u_cmd = { get ? GET_USB_INFOR_VIDPID : SET_USB_INFOR_VIDPID,value,0 };
m_usb->write_bulk(&u_cmd, sizeof(u_cmd));
if (get)
{
m_usb->read_bulk(&u_cmd, sizeof(u_cmd));
value = u_cmd.u32_Data;
}
}
}
void GScn_Drv::reset()
@ -383,7 +409,7 @@ DWORD GScn_Drv::usbmain()
DWORD transferCount = 0;
iNum++;
cv::Mat imgData = Get_Img_Data(totalNum);
switch(m_scannerType)
switch(m_scannerType)
{
case G100:
case G200:
@ -412,7 +438,12 @@ DWORD GScn_Drv::usbmain()
case G300:
case G400:
case G500:
{
pushMat(JpegBuffer(imgData, m_config.g200params.color == 1 ? TJPF_BGR : TJPF_GRAY,0,0));
//auto img = fopen("inmg.jpg", "wb+");
//fwrite(imgData.data, 1, totalNum, img);
//fclose(img);
}
break;
default:
break;
@ -431,7 +462,26 @@ DWORD GScn_Drv::usbmain()
{
m_isScanning = false;
devState = DEV_STOP;
MessageBox(NULL,TEXT("自动校正已完成!"), TEXT("提示"), MB_OK);
if (usbcb.u32_Count != 0)
{
std::string msg;
msg.resize(usbcb.u32_Count);
m_usb->read_bulk(&msg[0], usbcb.u32_Count);
if (m_flatcallback)
m_flatcallback(msg);
}
//MessageBox(NULL,TEXT("×Ô¶¯Ð£ÕýÒÑÍê³É£¡"), TEXT("Ìáʾ"), MB_OK);
}
case AUTO_FLATTING:
{
if (usbcb.u32_Count != 0)
{
std::string msg;
msg.resize(usbcb.u32_Count);
m_usb->read_bulk(&msg[0], usbcb.u32_Count);
if (m_flatcallback)
m_flatcallback(msg);
}
}
break;
case COUNT_MODE:

View File

@ -20,64 +20,64 @@ public:
GScn_Drv();
virtual ~GScn_Drv();
virtual void open(int vid, int pid, int index);
virtual int aquire_image(std::string& image, int num);
virtual bool IsConnected();
virtual std::string GetFWVersion();
virtual void SetFWVersion();
virtual std::string GetSerialNum();
virtual void SetSerialNum(std::string serial);
virtual std::string GetKernelVersion();
virtual void SetRatio(int tyepe, int ration);
virtual void GetRatio(int type, int& ratio);
virtual void Reboot();
virtual void open(int vid, int pid, int index)override;
virtual int aquire_image(std::string& image, int num)override;
virtual bool IsConnected()override;
virtual std::string GetFWVersion()override;
virtual void SetFWVersion()override;
virtual std::string GetSerialNum()override;
virtual void SetSerialNum(std::string serial)override;
virtual std::string GetKernelVersion()override;
virtual void SetRatio(int tyepe, int ration)override;
virtual void GetRatio(int type, int& ratio)override;
virtual void Reboot()override;
virtual void PowerOff() {};
virtual bool is_scan();
virtual bool Get_Scanner_PaperOn();
virtual bool is_scan()override;
virtual bool Get_Scanner_PaperOn()override;
virtual void Config_Scanner(PUSBCB pUSBCB);
virtual void Config_Scanner(HGScanConfig config);
virtual void Scanner_StartScan(UINT16 count);
virtual void Stop_scan();
virtual void ResetScanner();
virtual bool Get_IsImageQueueEmpty();
virtual void reset();
virtual void run();
virtual void ActiveteUSB();
virtual bool Updata(std::string filename, std::function<void(long, long)> func);
virtual void Config_Scanner(HGScanConfig config)override;
virtual void Scanner_StartScan(UINT16 count)override;
virtual void Stop_scan()override;
virtual void ResetScanner()override;
virtual bool Get_IsImageQueueEmpty()override;
virtual void reset()override;
virtual void run()override;
virtual void ActiveteUSB()override;
virtual bool Updata(std::string filename, std::function<void(long, long)> func)override;
virtual int GetScanNum();
virtual int GetScanNum()override;
virtual void ClrRollerNum();
virtual void ClrRollerNum()override;
virtual void ClrScanNum();
virtual void ClrScanNum()override;
virtual void SendFlatData(CorrectParam param, int index);
virtual void SendFlatData(CorrectParam param, int index)override;
virtual CaptureParams GetFlatData();
virtual CaptureParams GetFlatData()override;
virtual void StartFlat(bool iscolor);
virtual void StartFlat(bool iscolor)override;
virtual void DevStateChange();
virtual void DevStateChange()override;
virtual int getMatSum();
virtual int getMatSum()override;
virtual void close();
virtual void close()override;
virtual void GetExpose(int& Aside, int& Bside);
virtual void SetExpose(int aside, int bside);
virtual void GetExpose(int& Aside, int& Bside)override;
virtual void SetExpose(int aside, int bside)override;
virtual void GetSptime(int type, int& time);
virtual void SetSptime(int type, int time);
virtual void GetSptime(int type, int& time)override;
virtual void SetSptime(int type, int time)override;
virtual void GetSleepTime(int& sleeptime);
virtual void SetSleepTime(int sleeptime);
virtual void GetSleepTime(int& sleeptime)override;
virtual void SetSleepTime(int sleeptime)override;
virtual void GetFlatMaxBright(bool iscolor, unsigned int& val);
virtual void SetFlatMaxBright(bool iscolor, unsigned int val);
virtual void SetFlatCallback(std::function<void(std::string)> func);
virtual void GetSpeedMode(int& speedmode, bool get);
virtual void GetFlatMaxBright(bool iscolor, unsigned int& val)override;
virtual void SetFlatMaxBright(bool iscolor, unsigned int val)override;
virtual void SetFlatCallback(std::function<void(std::string)> func)override;
virtual void GetSpeedMode(int& speedmode, bool get)override;
virtual void GetOrSetVIDPID(int& value, bool get) override;
private:
volatile int devState;
volatile bool m_bRun;

BIN
HuaGoCorrect/img.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 MiB

BIN
HuaGoCorrect/inmg.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 MiB

View File

@ -0,0 +1,35 @@
#include "stdafx.h"
#include "vendorconfig.h"
#ifdef WIN32
#include <io.h>
#endif // WIN32
const char* vendorfile = "./vendorjson.json";
VendorConfig::VendorConfig()
{
if (access(vendorfile, 0) != 0)// not exist
{
}
}
VendorConfig::~VendorConfig()
{
}
std::vector<ScanerVendor> VendorConfig::GetVendorList()
{
return m_suprtvendor;
}
void VendorConfig::AddVendor(ScanerVendor& vendor)
{
}
void VendorConfig::createdefaultvendor()
{
}

View File

@ -0,0 +1,27 @@
#pragma once
#include "json.h"
#include <vector>
#include <sstream>
typedef struct ScanerVendor
{
std::string Vendor;
unsigned short VID;
unsigned short PID;
};
class VendorConfig
{
public:
VendorConfig();
~VendorConfig();
std::vector<ScanerVendor> GetVendorList();
void AddVendor(ScanerVendor& vendor);
private:
void createdefaultvendor();
//void read
private:
std::vector<ScanerVendor> m_suprtvendor;
};