磁动力电子网-雕刻机DIY论坛,单片机论坛,CNCDIY,DIYCNC

 找回密码
 加入磁动力

QQ登录

只需一步,快速开始

扫一扫,访问微社区

查看: 7596|回复: 45

答网友问(关于CD-ROM控制器)

[复制链接]
发表于 2004-8-8 09:33:00 | 显示全部楼层 |阅读模式

一些朋友在问起ATAPI的东西,在这我只想说说我的认识,我对些也不算很熟悉,只是抽空看了CD播放部分的。也有很多朋友也写了汇编的源码,我写的C有不量的注解,大家有兴趣可以参考,当然也有一些BUG,限于时间我也没做多大的完善,希望有兴趣的朋友修改后可以把程序贴上来大家一起参考再修改。

//-------------------------------------------// // ATAPI-CDROM 驱动程序 // // // // 这源码为ATAPI基本驱动程序,main()中只有 // // 几个基本功能,为演示版,存在一些很多BUG // // // // 本程序为共享版本,但不得用于商业性质。  // // // // 不提供任何无偿的技术支持。        // // 使用或转载时请保留些版权信息。 // // 更多升级版本请留意: // // 主页:http://www.cdle.net // // 论坛:http://bbs.cdle.net // // // // 联系方式:pnzwzw@cdle.net // // pnzwzw@163.com // // // //版权所有 http://www.cdle.net 2001-2004 明浩// //-------------------------------------------// #include <at89x51.h>

#define A0 P0_0 #define A1 P0_1 #define A2 P0_2 #define CS0 P0_3 #define CS1 P0_4 #define WR P0_5 #define RD P0_6 #define RST P0_7 #define CDCOM P0 //CDROM控制线 #define INTRQ P3_7 //INTRQ #define DBM P2 //CDROM数据线高8位 #define DBL P1 //CDROM数据线低8位

//------------------------------------------// // // // P0.0--------------------------------P0.7 // // A0 A1 A2 CS0 CS1 WR RD ACT // // // //------------------------------------------// //用变量设置P0的值,以方便对应于各寄存器的地址值 #define REG_Data 0xE0 #define REG_Err 0xE1 //Features #define REG_Features 0xE1 #define REG_Sector 0xE2 #define REG_CyLow 0xE4 #define REG_CyHig 0xE5 #define REG_DriveHead 0xE6 #define REG_Status 0xE7 //Command #define REG_Command 0xE7 #define PLAYKey P3_2 #define EJECTKey P3_3 #define STOPKey P3_5 #define NEXTKey P3_4 #define PREVIOUSKey P3_6 #define ERRLED P3_7

unsigned char code ReadSubP[]={0x42,0x02,0x40,0x01,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00}; //ReadSub命令信息包 unsigned char code ReadTOCP[]={0x43,0x02,0x00,0x00,0x00,0x00,0x00,0x00,0x0C,0x00,0x00,0x00}; //ReadTOC命令信息包 unsigned char code PlayMSFP[]={0x47,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00}; //MSF播放命令信息包 unsigned char data PacketTemp[24]; //信息包暂存RAM,用写数据和读数据的暂存

unsigned char REGBL=0, REGBM=0; //用于暂存读取寄存器的值 unsigned char PacketSize; //用于保存CDROM定义的信息包长度,有12,16 unsigned char bdata CDStatusREG; //可位寻址变量保存CDROM的状态寄存器值 sbit ERR = CDStatusREG^0; //错误 sbit DRQ = CDStatusREG^3; //数据请求 sbit DRDY = CDStatusREG^6; //设备就绪 sbit BSY = CDStatusREG^7; //忙

unsigned char bdata CDErr=0; //保存各种错误标识 sbit INITERR = CDErr^0; //初始化错误 sbit TESTERR = CDErr^1; //CDROM自身诊断错误 sbit UKERR = CDErr^2; //未知错误 sbit EJECTING = CDErr^3; //弹出 sbit CDOK = CDErr^4; //CD就绪 sbit PLAYING = CDErr^5; sbit PAUSEING = CDErr^6; sbit STOPING = CDErr^7;

unsigned char DEV; //选择驱动器时所用的参数 unsigned char AudioStatus; //当前的播放状态 unsigned char StartTrackNum; //开始曲目 unsigned char EndTrackNum; //结束曲目 unsigned char CurrentTrackNum; //当前曲目 unsigned char CurrentM, CurrentS, CurrentF; //当前MSF值 unsigned char StartM, StartS, StartF; //开始的MSF值 unsigned char EndM, EndS, EndF; //结束的MSF值

void dmsec(unsigned int msec); void RedREG(unsigned char REG); void WriREG(unsigned char LSB, unsigned char MSB, unsigned char REG); void SendPacket(unsigned char SkipDRQ); void TestCD(void); void ReadSub(void); void ReadTOC(unsigned char Track); void ResData(unsigned char Count); void ReadStatus(void); void InitCDROM(void); void BSYWait(void); //void INTRQWait(void); void DRQWait(void); void NDRQWait(void); void LoadPacket(unsigned char code *RT); void TestUnitReady(void); void PlayMSF(void); void Eject(unsigned char EJ); void Pause(unsigned char PR); void Next(unsigned char NP); void Stop(void);

void main(void) { InitCDROM();

do { if (!PLAYKey) //play or pause 要求CD就绪才响应 { if (CDOK) { dmsec(20); //延时20ms防抖动 if (!PLAYKey) { if (PLAYING) //CD正在播放中的处理 { if (PAUSEING) //继续播放 { Pause(0); PAUSEING = 0; } else //暂停播放 { Pause(1); PAUSEING = 1; } } else //CD就绪按play后播放 { ReadTOC(CurrentTrackNum); //读当前TOC ReadTOC(0xAA); PlayMSF(); //播放 PLAYING = 1; //标识 } } } dmsec(2000); }

if (!STOPKey) //当CD在播放中 { if (PLAYING) { dmsec(20); if (!STOPKey) { Pause(1); //暂停 Stop(); PLAYING = 0; PAUSEING = 0; } } dmsec(2000); }

if (!NEXTKey) { if (PLAYING) { dmsec(20); if (!NEXTKey) { Next(1); } } dmsec(2000); }

if (!PREVIOUSKey) { if (PLAYING) { dmsec(20); if (!PREVIOUSKey) { Next(0); } } dmsec(2000); }

if (!EJECTKey) { dmsec(20); if (!EJECTKey) { if (EJECTING) { Eject(3); //装载 EJECTING = 0; dmsec(3000); InitCDROM(); } else { Eject(2); EJECTING = 1; CDOK = 0; PAUSEING = 0; PLAYING = 0; STOPING = 0; } } dmsec(2000); }

ReadStatus();//读状态 ERRLED = ~ERR; //ERR指示 } while(1); }

//1ms延时 11.0592MHz /不是太精确 void dmsec(unsigned int msec) { unsigned int TempCyc; while(msec--) { for(TempCyc=0; TempCyc<125; TempCyc++); } }

//写寄存器 void WriREG(unsigned char LSB, unsigned char MSB, unsigned char REG) { CDCOM = REG; //设要写的REG //EA=0;//程序中有中断程序时应先关中断 CS1 = 1; DBL = LSB; DBM = MSB; //写数据 WR = 0; WR = 1; CS1 = 0; //WD,CS1置回 DBL = 0xFF; DBM = 0xFF; dmsec(3); //延时 //EA=1; 在这开中断 }

//读寄存器 void RedREG(unsigned char REG) { CDCOM = REG; //设要读的寄存器 //EA=0;//程序中有中断程序时应先关中断 CS1 = 1; RD = 0; //开始读数据线 REGBL = DBL; //从数据线上读状态寄存器值 REGBM = DBM; RD = 1; CS1 = 0; //RD,CS1置回 dmsec(3); //延时 //EA=1; 在这开中断 }

//Count向CDROM发送信息包的大小 void SendPacket(unsigned char SkipDRQ) { unsigned char TempCyc;

if (!SkipDRQ) NDRQWait(); WriREG(PacketSize, 0xFF, REG_CyLow); //设CyLow,CyHig的值不应小于传输的数量否则PacketCommand时ERR出错 WriREG(0x00, 0xFF, REG_CyHig); // WriREG(DEV, 0xFF, REG_DriveHead); //选择Device 0 WriREG(0xA0,0xFF,REG_Command); //发送A0H,Packet命令,准备发送Packet DRQWait(); //注:有些命令可能返回没有就绪的错误,这里没做考虑 for (TempCyc=0; TempCyc<PacketSize; TempCyc++) { CDCOM = REG_Data; //设控制IO,CS0-1=0,A0-2=0,WR-RD=1,RST=1 //EA=0;//程序中有中断程序时应先关中断 CS1 = 1; //这时CS1=1,CS0=0,A0-2=0,为选择数据寄存器Data Register DBL = PacketTemp[TempCyc*2]; DBM = PacketTemp[TempCyc*2+1]; //写信息包数据 WR = 0; WR = 1; CS1 = 0; //WR,CS1置回 DBL = 0xFF; DBM = 0xFF; dmsec(3); //延时 //EA=1; 在这开中断 } ReadStatus(); //返回当前状态 //INTRQWait(); //等待CDROM中断 }

//返回数据,Count为返回数据的多少 void ResData(unsigned char Count) { unsigned char TempCyc; for (TempCyc=0; TempCyc<Count; TempCyc++) { CDCOM = REG_Data; //设控制IO,CS0-1=0,A0-2=0,WR-RD=1,RST=1 //EA=0;//程序中有中断程序时应先关中断 CS1 = 1; //这时CS1=1,CS0=0,A0-2=0,为选择数据寄存器Data Register RD = 0; //开始读数据线 PacketTemp[TempCyc*2] = DBL; PacketTemp[TempCyc*2+1] = DBM; RD = 1; CS1 = 0; //WR,CS1置回 dmsec(3); //延时 //EA=1; 在这开中断 }

}

//读当前CDROM状态 void ReadStatus(void) { RedREG(REG_Status);//读状态寄存器 CDStatusREG = REGBL; //放入可寻址位方便使用 }

//读曲目TOC void ReadTOC(unsigned char Track) { unsigned char TempCyc = 0;

LoadPacket(ReadTOCP); //暂存数据到RAM PacketTemp[6] = Track; //要读取的轨道,值为0H-63H,写AAH为返回开始区段值 SendPacket(0); //向CDROM送信息包 ResData(12);//返回数据4字节

StartTrackNum = PacketTemp[2]; //读首曲目数字 EndTrackNum = PacketTemp[3]; //读尾曲目数字

if (Track == 0xAA) { EndM = PacketTemp[9]; //读曲目的MSF值 EndS = PacketTemp[10]; EndF = PacketTemp[11]; } else { StartM = PacketTemp[9]; StartS = PacketTemp[10]; StartF = PacketTemp[11]; } }

//播放MSF void PlayMSF(void) { LoadPacket(PlayMSFP); //暂存数据到RAM PacketTemp[3] = StartM; //写MSF值 PacketTemp[4] = StartS; PacketTemp[5] = StartF; PacketTemp[6] = EndM; PacketTemp[7] = EndS; PacketTemp[8] = EndF; SendPacket(0); //向CDROM送信息包 }

//弹出、装入 void Eject(unsigned char EJ) { LoadPacket(PlayMSFP); //暂存数据到RAM PacketTemp[0] = 0x1B; //START/STOP UNIT Command字节 PacketTemp[4] = EJ; //EJ=0为停止,1为开始并读次信道,2为弹出托盘,3为装载光盘 SendPacket(1); //向CDROM送信息包 }

//暂停或继续 void Pause(unsigned char PR) { LoadPacket(PlayMSFP); //暂存数据到RAM PacketTemp[0] = 0x4B; //PAUSE/RESUME Command PacketTemp[8] = ~PR; //PR为1时暂停 SendPacket(0); //向CDROM送信息包 }

//停止 void Stop(void) { LoadPacket(PlayMSFP); //暂存数据到RAM PacketTemp[0] = 0x4E; //STOP/SCAN Command SendPacket(0); //向CDROM送信息包 }

//前进或后退 void Next(unsigned char NP) { ReadSub(); //读当前曲目 if (NP) //计算 NP = CurrentTrackNum + 1; else NP = CurrentTrackNum - 1; if (NP < StartTrackNum) NP = StartTrackNum; if (NP > EndTrackNum) NP = EndTrackNum; ReadTOC(NP); //读下一首或前一首的TOC PlayMSF(); //播放 }

//读次信道信息 void ReadSub(void) { LoadPacket(ReadSubP); //暂存数据到RAM SendPacket(0); //向CDROM送信息包 ResData(12);//返回数据16字节 AudioStatus = PacketTemp[1]; CurrentTrackNum = PacketTemp[6]; CurrentM = PacketTemp[9]; CurrentS = PacketTemp[10]; CurrentF = PacketTemp[11]; }

//检查CDROM是否就绪 void TestUnitReady(void) { unsigned char TempCyc; unsigned char TempS;

for (TempCyc = 0; TempCyc < 12; TempCyc++) PacketTemp[TempCyc] = 0x00; //Packet for Test Unit Ready Command do { SendPacket(1); //因可能CDROM不在就绪状态所以跳过DRQ检测 TempS = CDStatusREG & 0x89; //CDStatusREG & 0x89为判断ERR,DRQ,BSY中是否有1 } while(TempS); //PacketCommand失败时认为CDROM没就绪,再次发送Test Unit Ready Command }

//初始化CDROM void InitCDROM(void) { //--------------------------------- // 复位 //--------------------------------- DBL = 0xFF; DBM = 0xFF; RST = 0; //拉低RST,延时使CDROM复位 dmsec(100); //延时 RST = 1; //复位完成拉高RST dmsec(5000); //延时

//--------------------------------- // 选择Device 0 //--------------------------------- //Drive/Head寄存器D4位控制设备的选取 RedREG(REG_DriveHead); //读Drive/Head寄存器 DEV = REGBL & 0xEF; //读出Drive/Head寄存器值并把D4位清零 WriREG(DEV, 0xFF, REG_DriveHead); //把值写回Drive/Head寄存器

//--------------------------------- // 校验CylLow和CyHig寄存器 //--------------------------------- //CDROM正常复位后CylLow的值为14H,CylHig的值为EBH,不对是说明设备出错 RedREG(REG_CyLow); //读CyLow寄存器 if (REGBL == 0x14) { RedREG(REG_CyHig); //读CyHig寄存器 if (REGBL != 0xEB) INITERR = 1; } else { INITERR = 1; }

if (!INITERR) { //--------------------------------- // 执行自身诊断 //--------------------------------- WriREG(0x90,0xFF,REG_Command); //写Command寄存器,90H为执行设备诊断 BSYWait(); RedREG(REG_Err); //读Error寄存器 if ((REGBL != 0x01) && (REGBL != 0x81)) TESTERR = 1; //当返回值不等于01H或81H时则说明CDROM自身诊断未通过,这里只考虑Device0

//--------------------------------- // 使能数据包(Packer Command)功能 // IDENTIFY PACKET DEVICE //--------------------------------- WriREG(0xA1,0xFF,REG_Command); //写A1H,IDENTIFY PACKET DEVICE命令 //INTRQWait(); //等待CDROM中断 RedREG(REG_Data); //读一个字节的返回数据用于判断CDROM所定义的Packet长度 REGBL = REGBL << 6; if (REGBL == 0x00) PacketSize = 6; //12byte 6word if (REGBL == 0x40) PacketSize = 8; //16byte 8word if (!PacketSize) UKERR = 1; //当不是这两个值是为未知错误 }

TestUnitReady(); ERRLED = 0; ReadSub(); //读信息 BSYWait(); ERRLED = 1; if (CurrentTrackNum==0x01) //当前曲目应等于1 CDOK = 1; else CDOK = 0; }

//检测忙状态 void BSYWait(void) { do { ReadStatus(); } while(BSY); }

/*检测INTRQ引脚,CDROM中断 void INTRQWait(void) { do { INTRQ = 1; } while(INTRQ); } */

//检测DRQ是否为1,BSY=0 void DRQWait(void) { do { BSYWait(); DRQ = ~DRQ; } while(DRQ); }

//检测DRQ是否为0,BSY=0 void NDRQWait(void) { do { BSYWait(); } while(DRQ); }

//数据包送暂存RAM void LoadPacket(unsigned char code *RT) { unsigned char TempCyc;

for (TempCyc=0; TempCyc<12; TempCyc++) //数据包送暂存RAM { PacketTemp[TempCyc] = *RT; RT++; } }

[此贴子已经被作者于2004-8-10 8:28:21编辑过]

回复

使用道具 举报

 楼主| 发表于 2004-8-8 09:48:00 | 显示全部楼层

也有朋友问ATAPI的寄存器分布,开关仓门的命令等

首先在http://www.cdle.net/alldata/mywz/04050701_1.htm有一些资料

下面的图来自我还未发表的文章中一段,是ATAPI的部分寄存器说明

答网友问(关于CD-ROM控制器)

答网友问(关于CD-ROM控制器)

关于开关仓门的命令有好几种具体的方法,我使用的是start/stop unit 命令,命令字是0x1B,可以参考上贴中的Eject函数

//弹出、装入 void Eject(unsigned char EJ) { LoadPacket(PlayMSFP); //暂存数据到RAM PacketTemp[0] = 0x1B; //START/STOP UNIT Command字节 PacketTemp[4] = EJ; //EJ=0为停止,1为开始并读次信道,2为弹出托盘,3为装载光盘 SendPacket(1); //向CDROM送信息包 }

回复 支持 反对

使用道具 举报

发表于 2004-8-9 19:52:00 | 显示全部楼层

谢明浩。我要消化它。写出汇编再贴出来,有问题还要问。

回复 支持 反对

使用道具 举报

 楼主| 发表于 2004-8-10 11:47:00 | 显示全部楼层

应该是先发送mode sense command(要设置为更改状态),再向DATA寄存器发送mode page参数,也就是你贴出来的图

具体我也就没试过,你有空可以试试看

[此贴子已经被作者于2004-8-10 16:56:13编辑过]
回复 支持 反对

使用道具 举报

发表于 2004-8-10 12:30:00 | 显示全部楼层
以下是引用明浩在2004-8-10 11:47:47的发言:

应该是先发送mode sense command(要设置为更改状态),再向DATA寄存器发送mode page参数,也就是你贴出来的图

具体我也就试过,你有空可以试试看

还是有点不明白,mode sense command我只用过它来读过光盘识别信息,没有做过其他的。楼主能否说详细点,最好有命令执行流程,或者是给个代码看看,先谢谢了!

回复 支持 反对

使用道具 举报

发表于 2004-8-10 14:16:00 | 显示全部楼层
我按照你的思路写了代码,但还是没有办法控制啊!程序进入音量控制程序后就死机了,郁闷!
回复 支持 反对

使用道具 举报

发表于 2004-8-10 10:21:00 | 显示全部楼层
 明浩你好,我想为CDROM做个遥控音量控制,在SFF8020I上见到有音量控制页,见下面:

答网友问(关于CD-ROM控制器)

答网友问(关于CD-ROM控制器)

   但是看了很久的mode sense command和mode select command ,就是没有搞明白怎么控制.关键是配置页怎么写,还请楼主看一下.有兴趣可以一起来研究啊!^^
回复 支持 反对

使用道具 举报

 楼主| 发表于 2004-8-10 16:58:00 | 显示全部楼层

打错了,我是说我没试过呀

回复 支持 反对

使用道具 举报

发表于 2004-8-10 19:33:00 | 显示全部楼层
好象不是你说的那么简单,反正这样是不行的.mode_sense_cmd是从光驱中得到mode page参数的,你发了mode_sense_cmd命令后,接下来应该要读数据寄存器,怎么可能就写数据呢?要是mode_select_cmd还可以写数据的,文档上说这两个命令要结合使用,但究竟怎么样用,还是不明白.
回复 支持 反对

使用道具 举报

发表于 2004-8-11 14:01:00 | 显示全部楼层
今天做了实验,在WINDOWS状态下能很好地控制CDROM面板上的模拟音量,所以,肯定有命令来控制的。我看就是要用MODE SELECT COMMAMD这个命令来修改的,但是每次我用这个命令后就出错,真是郁闷,明浩大哥,快帮帮我吧!
回复 支持 反对

使用道具 举报

 楼主| 发表于 2004-8-11 15:16:00 | 显示全部楼层

你的代码怎么写

回复 支持 反对

使用道具 举报

发表于 2004-8-16 23:03:00 | 显示全部楼层

明基的40x ,48x(翻盖面板的)好象是用飞利蒲转盘

回复 支持 反对

使用道具 举报

 楼主| 发表于 2004-8-16 08:39:00 | 显示全部楼层

每个曲目都可以读取一个MSF值,这个值是曲目的开始值,如要判断2号曲目是否已播放结束,那么就要读取3号曲目的MSF值,当到达这个值时表明2号曲目已结束。要判断最后一个曲目的结束,则要读取0xAA号的MSF值,它是代表最后的MSF值。曲目的有效值是1-99,0xaa则是表示结束的MSF

回复 支持 反对

使用道具 举报

发表于 2004-8-16 12:12:00 | 显示全部楼层

read_subchan_cmd: mov a,#10h ;set byte counter register lcall set_cyl_low_bitister ;= 16 bytes lcall set_cyl_high_bitister ; lcall do_packet_cmd mov packet_cmd,#42h mov packet_1,#00000010b ;MSF=1 mov packet_2,#01000000b ;SubQ=1 mov packet_3,#01h ;format=01 (current position) mov packet_8,#016h ;allocation length (16 bytes) lcall send_packet jb STATUS_bit_DRQ,read_subchan_cmd_r read_subchan_cmd_e: mov audio_status,#0ffh ret ;read Current Audio track,MSF

read_subchan_cmd_r: lcall get_data ;get audio status mov audio_status,b lcall get_data ;sub channel data length (will be zero).. ignore lcall get_data ;data format,adr/fiel lcall get_data ;current track ,index track mov current_track,a lcall get_data ;M mov current_M,b lcall get_data ;SF mov current_S,a mov current_F,b lcall skip_rest_of_packet ret

我用以上的程序来判断当前的播放状态,这个程序的返回值有五个。audio_status、current_track、current_M、current_S、current_F。

audio_status是当前播放的状态:;11h播放中、12h暂停、13h播放完毕、14h出错、15h没有声音数据。

current_track是当前播放的轨道

还有三个是进行的时间。

我每间隔0.1秒去读一次状态,用为显示时间和状态的判断。

这个已经解决了,最后一个问题是怎样判断盘片的类型。

回复 支持 反对

使用道具 举报

发表于 2004-8-16 17:44:00 | 显示全部楼层
现在所有问题都解决了。想问一下用飞利蒲转盘12.X的光驱型号有那些?我想把家中的那台坏了光头的CD机改装一下,读片部分用光驱代替,后面加DAC。
[此贴子已经被作者于2004-8-16 17:45:31编辑过]
回复 支持 反对

使用道具 举报

发表于 2004-8-15 10:42:00 | 显示全部楼层
调了两个小时,停止、播放、等基本的功能正常了。不知怎样控制快进和快退。还有在播放中怎样判断该曲目已播放结束?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2004-8-14 12:46:00 | 显示全部楼层

是的,是这样做的。

回复 支持 反对

使用道具 举报

发表于 2004-8-14 11:58:00 | 显示全部楼层

浩哥,你的音量控制的步骤是: 1.在单片机RAM中准备好命令(mode sense) 2.发送命令(SendPacket) 3.读取CDROM中 0E页数据到单片机中指定的RAM(24个字节) 4.修改指定RAM中的音量等值(4个字节内容) 5.在单片机RAM中准备好命令(mode select) 6.发送命(SendPacket) 7.向DATA寄存器写入第4步指定RAM中的数据(24个字节) 8.光驱音量发生改变 这样对吗.

回复 支持 反对

使用道具 举报

 楼主| 发表于 2004-8-13 18:07:00 | 显示全部楼层

我那晚开始时也是发了一些不对格式的数据和参数不正确就有问题了,不是没声,这是忽大忽小乱套了,读出的数据也不对。后来我用现在方法就很好了。

回复 支持 反对

使用道具 举报

发表于 2004-8-13 11:53:00 | 显示全部楼层
明浩大哥,你的程序是在仿真器上运行还是在单片机上运行的呀?我有一个想法,怎么跳过其他字节而直接写音量控制数据呢?其实好多数据是没有必要再写的呀!只要改音量数据就行了.郁闷,试了N次,还是一发命令就没有声音,然后从mode sense command返回的数据是乱的.真想再试下你的电路和原代码.
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 加入磁动力

本版积分规则

QQ|小黑屋|手机版|Archiver|www.cdle.net 磁动力电子网 2001-2017 ( 粤ICP备10098153号

粤公网安备 44040402000001号

GMT+8, 2019-3-21 01:16

Powered by Discuz! X3.2 Licensed

© 2001-2013 Comsenz Inc.