Interfacing with Dicom sistems

User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Re: Interfacing with Dicom sistems

Post by xProgrammer »

Hi all (and especially Massimo)

Whilst I don't have access to a DICOM based camera just at the moment (but will have soon), I have started writing some code with a view to making a start on this project.

I have written a base class (TDicomVR) for a DICOM value representation (VR). I would intend deriving classes for the various types (27 ?) of value representations from this base class.

To date I have written three such derived classes: TDicomVRUI (unique identifier), TDicomVRUL (unsigned long) and TDicomVRUS (unsigned short). These were picked to enable me to build a C-Echo Request class (TEchoReqBody).

I have not yet written any code to actually send this request out on the LAN/WAN nor to capture and decode the expected response.

The following code includes the above classes and uses them to build a C-Echo Request as per the book referenced in above posts and the string it builds matches that given in a table in the book with the exception of 1 byte which I think represents an error in the book.

Code: Select all | Expand

// dicom.prg// initial experimental code aiming for DICOM capabilities from software written in [x]Harbour.#include "hbclass.ch"FUNCTION Main()  obj_ThisBody := TCEchoReqBody():New( "0020" )  ShowByteStream( obj_ThisBody:ByteStream() )  InKey( 0 )  QUIT/**************************************************************\*                                                              **    CLASS TCEchoReqBody - DICOM C-Echo Request (DICOM-ping)   **                                                              **  Used to verify one DICOM AE is connected to another         **                                                              *\**************************************************************/CLASS TCEchoReqBody  DATA obj_GroupLength  DATA obj_AffServClassUID   DATA obj_CommandField      DATA obj_MessageID         DATA obj_DataSetType       METHOD New( var_ID )  METHOD ByteStream()ENDCLASSMETHOD New( var_ID ) CLASS TCEchoReqBody  LOCAL int_GroupLength  ::obj_AffServClassUID := TDicomVRUI():New( "0000", "0002", "1.2.840.10008.1.1" )  ::obj_CommandField    := TDicomVRUS():New( "0000", "0100", "0030" )  ::obj_MessageID       := TDicomVRUS():New( "0000", "0110", var_ID )  ::obj_DataSetType     := TDicomVRUS():New( "0000", "0800", "0101" )  int_GroupLength := ::obj_AffServClassUID:Length() + ::obj_CommandField:Length() + ::obj_MessageID:Length() + ::obj_DataSetType:Length()  ::obj_GroupLength     := TDicomVRUL():New( "0000", "0000", int_GroupLength )  RETURN selfMETHOD ByteStream() CLASS TCEchoReqBody  RETURN ::obj_GroupLength:ByteStream() + ::obj_AffServClassUID:ByteStream() + ::obj_CommandField:ByteStream() + ;    ::obj_MessageID:ByteStream() + ::obj_DataSetType:ByteStream()/**************************************************************\*                                                              **         CLASS TDicomVR - DICOM Value Representation          **                                                              **  This is the base class from which the various DICOM value   **  representations (there are currently 27 defined) are        **  derived.                                                    **                                                              *\**************************************************************/CLASS TDicomVR  DATA str_Group  DATA str_Element  DATA str_DataLength  DATA str_Data  METHOD New() CONSTRUCTOR  METHOD SetGroupHex( str_HexGroup )  METHOD SetElementHex( str_HexElement )   METHOD SetLength( int_Length )  METHOD ByteStream()  METHOD Length() ENDCLASSMETHOD New() CLASS TDicomVR  RETURN selfMETHOD SetGroupHex( str_HexGroup ) CLASS TDicomVR  LOCAL int_Group  int_Group := HexToNum( str_HexGroup )  ::str_Group := Chr( int_Group % 256 ) + Chr( Int( int_Group / 256 ) )  RETURN nilMETHOD SetElementHex( str_HexElement ) CLASS TDicomVR  LOCAL int_Element  int_Element := HexToNum( str_HexElement )  ::str_Element := Chr( int_Element % 256 ) + Chr( Int( int_Element / 256 ) )  RETURN nilMETHOD SetLength( int_Length ) CLASS TDicomVR  LOCAL int_ThisByte   int_ThisByte := int_Length % 256  ::str_DataLength := Chr( int_ThisByte )  int_Length := ( int_length - int_ThisByte ) / 256  int_ThisByte := int_Length % 256  ::str_DataLength += Chr( int_ThisByte )  int_Length := ( int_length - int_ThisByte ) / 256  int_ThisByte := int_Length % 256  ::str_DataLength += Chr( int_ThisByte )  int_Length := ( int_length - int_ThisByte ) / 256  int_ThisByte := int_Length % 256  ::str_DataLength += Chr( int_ThisByte )  RETURN nilMETHOD ByteStream() CLASS TDicomVR  RETURN ::str_Group + ::str_Element + ::str_DataLength + ::str_DataMETHOD Length() CLASS TDicomVR  RETURN 8 + Len( ::str_Data )/******************************************************************\*                                                                 ** CLASS TDicomVRUI - DICOM Value Representation Unique Identifier **                                                                 ** A character string containing a UID that is used to uniquely    ** identify a wide variety of items.                               **                                                                 *\******************************************************************/CLASS TDicomVRUI FROM TDicomVR  METHOD New( str_Data )ENDCLASSMETHOD New( str_Group, str_Element, str_Data ) CLASS TDicomVRUI  LOCAL int_Length   ::SetGroupHex( str_Group )  ::SetElementHex( str_Element )  // maximum acceptable length for data in a UI is 64 characters  int_Length := Len( str_Data )  IF int_Length > 64    str_Data := SubStr( str_Data, 1, 64 )    int_Length := 64  ENDIF  // data must be an even number of bytes - if odd pad with 0x00  IF int_Length % 2 == 1    str_Data += Chr( 0 )    int_Length += 1  ENDIF  // set data and length  ::str_Data := str_Data  ::SetLength( int_Length )  RETURN self/**************************************************************\*                                                              **  CLASS TDicomVRUL - DICOM Value Representation Unsigned Long **                                                              **  Unsigned binary integer 32 bits (4 bytes) in length         **                                                              *\**************************************************************/CLASS TDicomVRUL FROM TDicomVR  METHOD New( str_Group, str_Element, var_Data ) CONSTRUCTOR  METHOD Length()ENDCLASSMETHOD New( str_Group, str_Element, var_Data ) CLASS TDicomVRUL  LOCAL int_Data  ::SetGroupHex( str_Group )  ::SetElementHex( str_Element )  ::SetLength( 4 )    IF ValType( var_Data ) == "C"    int_Data := HexToNum( var_Data )   ELSE    int_Data := var_Data  ENDIF  int_ThisByte := int_Data % 256  ::str_Data := Chr( int_ThisByte )  int_Data := ( int_Data - int_ThisByte ) / 256  int_ThisByte := int_Data % 256  ::str_Data += Chr( int_ThisByte )  int_Data := ( int_Data - int_ThisByte ) / 256  int_ThisByte := int_Data % 256  ::str_Data += Chr( int_ThisByte )  int_Data := ( int_Data - int_ThisByte ) / 256  int_ThisByte := int_Data % 256  ::str_Data += Chr( int_ThisByte )  RETURN selfMETHOD Length() CLASS TDicomVRUL  RETURN 12/**************************************************************\*                                                              ** CLASS TDicomVRUS - DICOM Value Representation Unsigned Short **                                                              **  Unsigned binary integer 16 bits (2 bytes) in length         **                                                              *\**************************************************************/CLASS TDicomVRUS FROM TDicomVR  METHOD New( str_Group, str_Element, var_Data ) CONSTRUCTOR  METHOD Length()ENDCLASSMETHOD New( str_Group, str_Element, var_Data ) CLASS TDicomVRUS  LOCAL int_Data   ::SetGroupHex( str_Group )  ::SetElementHex( str_Element )  ::SetLength( 2 )    IF ValType( var_Data ) == "C"    int_Data := HexToNum( var_Data )   ELSE    int_Data := var_Data  ENDIF  ::str_Data := Chr( int_Data % 256 ) + Chr( Int( int_Data / 256 ) )  RETURN selfMETHOD Length() CLASS TDicomVRUS  RETURN 10  FUNCTION ShowByteStream( str_Stream )   LOCAL int_StreamLength  int_StreamLength := Len( str_Stream )  FOR ii = 1 TO int_StreamLength    ? "Byte", Str( ii, 3, 0 ), "=>", Str( Asc( str_Stream[ii] ), 3, 0), "Decimal or", NumToHex( Asc( str_Stream[ii] ), 2 ), "hex"  NEXT 


Any comments / suggestions happily received.
User avatar
Massimo Linossi
Posts: 508
Joined: Mon Oct 17, 2005 10:38 am
Location: Italy

Re: Interfacing with Dicom sistems

Post by Massimo Linossi »

Wow !!! You're really fast. Now i must ask if there is a way to go in that
clinic where there is a Dicom system and to go near the machine.
Maybe I can make some tests in a Pc connected in the net and assign it as a
fake server, not the main one.
I'll keep you informed if there are some possibilities to make this experiment.
Thanks a lot.
Massimo.
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Re: Interfacing with Dicom sistems

Post by xProgrammer »

Hi Massimo

I have some classes from my applications that access my [x]Harbour based client-server data base server that should adapt fairly easily to sending such a request and waiting for a reply, I think. But I need to know a bit more about the DICOM setup of the camera that I will have access to such as IP address (should be easy enough), port number(s). There may well be other setup details needed as well - I have to do more research in that area.

That code (as used to access data base server - that is not yet adapted to our prupose) is as follows:

Code: Select all | Expand

// Socket.prg#include "hbclass.ch"CLASS TSocket  CLASSDATA log_Initialised INIT .F.  DATA str_IPAddress  DATA int_PortNumber  DATA pSocket  DATA log_Connected  DATA str_Data  METHOD New() CONSTRUCTOR  METHOD SetIP( str_IPAddress )  METHOD SetPort( int_PortNumber )  METHOD CreateQueryObject()  METHOD Connect()  METHOD Send( cMessage )  METHOD Receive()  METHOD Close()  METHOD SendReceive( cMessage )  METHOD CleanUp()ENDCLASSMETHOD New() CLASS TSocket  ::str_IPAddress := "127.0.0.1"  ::int_PortNumber := 1800  IF !::log_Initialised     INetInit()     ::log_Initialised := .T.  ENDIF  RETURN selfMETHOD SetIP( str_IPAddress ) CLASS TSocket  ::str_IPAddress := AllTrim( str_IPAddress )  RETURN nilMETHOD SetPort( int_PortNumber ) CLASS TSocket  ::int_PortNumber := int_PortNumber  RETURN nilMETHOD CreateQueryObject()  RETURN( TQuery():New( self ) )METHOD Connect() CLASS TSocket  LOCAL log_OK  LOCAL log_Retry  log_Retry := .T.  DO WHILE log_Retry    log_OK := .T.    TRY      ::pSocket := INetConnect( ::str_IPAddress, ::int_PortNumber )    CATCH      MsgInfo( "Unable to connect to data server" )      log_OK := .F.    END    IF log_OK      IF INetErrorCode( ::pSocket ) == 0        ::log_Connected := .T.        RETURN .T.       ELSE        ? "Socket error:", INetErrorDesc( ::pSocket )      ENDIF    ENDIF    log_OK := .F.    ::log_Connected := .F.    // ? "Press [Esc] to exit, [Enter] to retry"    // IF InKey( 0 ) == 27    IF !MsgYesNo( "Emphasis can't communicate with the data server. Do you want to retry?", "Communication Error" )       INetCleanUp()      log_OK := .F.      ProgExit()    ENDIF  ENDDOMETHOD Send( var_Message ) CLASS TSocket  INetSend( ::pSocket, var_Message )  RETURN nilMETHOD Receive() CLASS TSocket  LOCAL str_Buffer  LOCAL int_Bytes  INetSetTimeOut( ::pSocket, 1000 )  ::str_Data := ""  int_Bytes := 1  DO WHILE int_Bytes > 0    ? "in loop"    str_Buffer := Space( 1024 )    int_Bytes := INetRecv( ::pSocket, @str_Buffer )    ? int_Bytes    ::str_Data += Left( str_Buffer, int_Bytes )  ENDDO  RETURN nilMETHOD Close() CLASS TSocket  INetClose( ::pSocket )  RETURN nilMETHOD SendReceive( cMessage ) CLASS TSocket  ::Send( cMessage )  ::Receive()  ::Close()  RETURN ::cDataMETHOD CleanUp() CLASS TSocket  RETURN InetCleanUp()


and

Code: Select all | Expand

// Query.prg/*added property oSocket to this class to support an application passingqueries to multiple servers*/#include "hbclass.ch"#include "rapids.ch"CLASS TQueryDATA arr_RequestDATA arr_TranslatedDATA int_ErrorLevelDATA log_RemoteDATA obj_SocketMETHOD New() CONSTRUCTORMETHOD Execute()METHOD ErrorText( int_ErrorNumber )METHOD ErrorList()ENDCLASSMETHOD New( obj_Socket ) CLASS TQuery::obj_Socket := obj_Socket::arr_Request := Array( 2 )::arr_Request[1] := Array( 2 )::arr_Request[1][2] := obj_User:str_Key::log_Remote := .T.RETURN selfMETHOD Execute( int_Query, arr_Parameters) CLASS TQuery  LOCAL log_Retry  // LOCAL tStart  // LOCAL tEnd  // tStart := Seconds()  ::int_ErrorLevel := 1  ::arr_Request[1][1] := int_Query  // ? "Query", iQuery  ::arr_Request[2] := arr_Parameters  DO WHILE ::int_ErrorLevel = dberrorclass_RETRY_OK    IF ::log_Remote      ::obj_Socket:Connect()      ? "about to send"      ::obj_Socket:Send( HB_Serialize( ::arr_Request) )       ? "waiting to receive"        ::obj_Socket:Receive()      ? "closing socket"      ::obj_Socket:Close()      ::arr_Translated := HB_Deserialize( ::obj_Socket:str_Data )     ELSE      // ::arr_Translated := MakeLocalQuery( ::arr_Request )    ENDIF    ::int_ErrorLevel := ::arr_Translated[1][1]    // ? "Return value", ::int_ErrorLevel    DO CASE      CASE ::int_ErrorLevel = dberrorclass_RETRY_OK        log_Retry := MsgYesNo( "Unable to write to database.  Do you want to retry?" )        IF log_Retry           ::int_ErrorLevel := dberrorclass_GAVE_UP        ENDIF      CASE ::int_ErrorLevel = dberrorclass_NO_RETRY         MsgInfo( "The database server has reported the following error(s):" + CRLF + ::ErrorList() )    ENDCASE  ENDDO  // time_End := Seconds()  // ? "start at", time_Start, "end at", time_End  RETURN ::int_ErrorLevelMETHOD ErrorText( int_ErrorNumber ) CLASS TQuery  DO CASE    CASE int_ErrorNumber = dberror_NO_ERROR      RETURN "No error has occurred"    CASE int_ErrorNumber = dberror_CANNOT_LOCK_RECORD              RETURN "Unable to obtain a record lock"    CASE int_ErrorNumber = dberror_CANNOT_APPEND_RECORD        RETURN "Unable to append to table"         CASE int_ErrorNumber = dberror_CANNOT_LOCK_FILE        RETURN "Unable to obtain a table lock"           CASE int_ErrorNumber = dberror_INVALID_KEY_ALLOCATOR            RETURN "Invalid key allocator specified"    CASE int_ErrorNumber = dberror_CANNOT_LOCK_LASTKEY_FILE         RETURN "Cannot obtain a lock on the key allocation table"    CASE int_ErrorNumber = dberror_NO_SUCH_KEY_VALUE                RETURN "No such key value"    CASE int_ErrorNumber = dberror_KEY_NOT_A_STRING                RETURN "The search value was not a string"    CASE int_ErrorNumber = dberror_NO_SUCH_QUERY_DEFINED           RETURN "No such query defined on this server"    CASE int_ErrorNumber = dberror_QUERY_IS_NOT_AN_ARRAY           RETURN "The query was received in an invalid (non-array) format"    CASE int_ErrorNumber = dberror_RECORD_HAS_CHANGED              RETURN "The record has been altered by another user"    CASE int_ErrorNumber = dberror_NO_ASSIGNED_KEY_ALLOCATOR       RETURN "No assigned key allocator"    OTHERWISE      RETURN "Unknown error"  ENDCASEMETHOD ErrorList() CLASS TQueryLOCAL arr_MessagesLOCAL int_NumMessagesLOCAL str_TextLOCAL int_MsgNumarr_Messages := ::arr_Translated[1][2]int_NumMessages := LEN( arr_Messages )str_Text := ""FOR int_MsgNum = 1 TO int_NumMessages   str_Text += "ERROR " + Str( arr_Messages[int_MsgNum] ) + ": " + ::ErrorText( arr_Messages[int_MsgNum] ) + CRLF NEXTRETURN str_Text


Obviously this code needs reworking for our current purposes, but it gives a rough idea of where we may be headed to get C-Echo Requests (and later DICOM requests) working.

I also remember that when I ran this code in a Windows environment (I use Linux almost exclusively) I had to make a small change to the way the software looped when receiving a reply.

Regards
xProgrammer
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Re: Interfacing with Dicom sistems

Post by xProgrammer »

Hi all

At this stage, presumably, the emphasis is on "proof of concept" - that is showing that we can interact successfully with other devices that implement DICOM from software written in [x]Harbour - rather than the elegance, efficiency and flexibility of our code. Nonetheless, perhaps we should start thinking about some of our goals in these regards. Some of my thoughts follow.

Some of the DICOM Value Representations have specific rules about what they should contain. To what extent should we check this and what should we do if the data passed in is non-conformant? Take the DA (Date) VR, a class for which might look like the following code (which was written quickly for this discussion and has not been tested) :

Code: Select all | Expand

/**************************************************************\*                                                              **    CLASS TDicomVRDA - DICOM Value Representation Date        **                                                              **  A date in the format YYYYMMDD                               **                                                              *\**************************************************************/CLASS TDicomVRDA FROM TDicomVR  METHOD New( str_Group, str_Element, var_Data ) CONSTRUCTOR  METHOD Length()ENDCLASSMETHOD New( str_Group, str_Element, var_Data ) CLASS TDicomVRDA  LOCAL int_Data   ::SetGroupHex( str_Group )  ::SetElementHex( str_Element )  ::SetLength( 2 )    IF ValType( var_Data ) == "D"    ::str_Data := DToS( var_Data )   ELSE    // string must be 8 characters long    // it should be in the format YYYYMMDD    ::Str_Data := PadR( var_Data, 8 )  ENDIF  RETURN selfMETHOD Length() CLASS TDicomVRDA  RETURN 16


If the date is passed in as an [x]Harbour date we don't have an issue here. But we probably want the flexibiity to pass in dates as character strings in the YYYYMMDD format which can be used directly. Length of the data is critical in DICOM, and we can ensure that is correct with the PadR function. But if the length is not 8 our code setting up the DICOM VR is presumably faulty. Should we rather return an error somehow to the requesting code?

And if we are going to check for errors do we check the string for only containing the characters [0-9]? And for being a valid date?

If a string being passed to one of the text VRs is over length do we just trim it to the maximum length or flag this as an error? Should such behaviour be optional and controlled by some parameter?

Regards
xProgrammer
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Re: Interfacing with Dicom sistems

Post by xProgrammer »

Hi all

Please note that whilst this project will, if successful, become important to me, I have lots of higher priority tasks to attend to, so I have to fit it into odd times in the evenings or mornings mostly. Also access to DICOM systems, whilst it will be available, will be limited, especially during early testing, as we can't afford to crash cameras or processing stations whilst they are being used for medical purposes. So don't expect too much too soon.

Regards
xProgrammer
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Re: Interfacing with Dicom sistems

Post by xProgrammer »

Hi all

If and when we manage to get C-Echo-Rq working, the next thing to try is probably C-Find-Rq, partly because of its function, and partly because a detailed, worked example is given in appendix A.3 (page 359 on)

Regards
xProgrammer
LEADTOOLS Support
Posts: 1
Joined: Wed Jan 27, 2010 4:12 pm

Re: Interfacing with Dicom sistems

Post by LEADTOOLS Support »

Massimo Linossi wrote:Thanks Frose.
I'm reading the file you linked. I don't really know how this can be
implemented in a Xharbour program. I'm looking at the Leadtools
forum and there are the 99% of the questions that are about the
imaging process and not the patients study database.
I'll look around in the web this weekend trying to find a solution.
Thanks again.



Massimo,

I am not sure when the last time you have used LEADTOOLS was, but we have a complete toolkit for DICOM and DICOM communication. Some of our latest additions provide high level components that handle all of the DICOM specific communication for you, so you only have to write the integration portion. There are many fully functional demos to help you get started as well.

I urge you to visit us at the below link, and download an evaluation.

http://leadtools.com/sdk/pacs-imaging.htm
http://support.leadtools.com/SupportPor ... Forum.aspx

LEADTOOLS Support
LEAD Technologies Inc.
http://www.leadtools.com/
http://support.leadtools.com/cs/forums/
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Re: Interfacing with Dicom sistems

Post by xProgrammer »

My understanding is that Leadtools is platform (ie Windows) dependant so that being the case it wouldn't be an option that I would consider (as my application runs on Linux), but it might suit others.

Regards
xProgrammer
User avatar
Massimo Linossi
Posts: 508
Joined: Mon Oct 17, 2005 10:38 am
Location: Italy

Re: Interfacing with Dicom sistems

Post by Massimo Linossi »

I looked into the forum, and I didn't found a solution for answering a Dicom
request for the patients list. There are a lot of examples about the imaging and
other problems. Xprogrammer, I think your approach is much better, for having
something that can work in different OS. And easy to change too, if the customer
ask you to add some different features. If I can help you in some way I'm here.
Thanks a lot.
Massimo.
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Re: Interfacing with Dicom sistems

Post by xProgrammer »

Hi Massimo

Last night I started on code to send the DICOM messages and receive replies. Maybe 2 weeks before I have an opportunity to test. Will also start on code to decipher replies (which I should be able to test using a dummy reply).

Regards
xProgrammer
User avatar
Massimo Linossi
Posts: 508
Joined: Mon Oct 17, 2005 10:38 am
Location: Italy

Re: Interfacing with Dicom sistems

Post by Massimo Linossi »

It's a pity that you are so far, otherwise we can go to work in my customer's clinic.
If you can make a little test program for receiving the request for the patients
worklist and then send it back to the Dicom machine, I can make some debug
and eventually rearrange the code for that specific procedure.
Thanks again.
Massimo.
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Re: Interfacing with Dicom sistems

Post by xProgrammer »

Hi Massimo

I've planned out some changes to my DICOM classes to allow the one object to handle both received and transmitted data, as the originator or the respondent. But this week coming up is very busy for me with high priority jobs so don't expect much progress for a week.

Regards
xProgrammer
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Re: Interfacing with Dicom sistems

Post by xProgrammer »

Hi Massimo

Installation of new DICOM workstation was delayed - expected within the next two weeks - will keep you informed of any progress.

Regards
xProgrammer
IVAN TRACHTA
Posts: 44
Joined: Fri Feb 03, 2006 6:42 pm
Location: FORMOSA - ARGENTINA

Re: Interfacing with Dicom sistems

Post by IVAN TRACHTA »

Hi
Are there any developments regarding this topic?

I need to develop an interface between my patient administration software and equipment based on DICOM.
The mechanism appears to be using HL7 but do not know how to deploy.
The idea is to export the data from patients directly to DICOM equipment.
Appreciate to know what's new. Thanks in advance

Iván
User avatar
xProgrammer
Posts: 464
Joined: Tue May 16, 2006 7:47 am
Location: Australia

Re: Interfacing with Dicom sistems

Post by xProgrammer »

Hi Ivan

I haven't touched my DICOM code for some time now as other projects took priority. When I last used it I had it correctly requesting a session, processing the reply, requesting a session close and getting the acknowledgment.

I wasn't getting a response to a request for a list of scans so there must have been some little problem there somewhere.

Happy to share what I have. And I will get back to it some time in the not too distant future.

As it so happens I now need (as a higher priority) to write some code to generate HL7. For this application it just needs to be written as a file and dumped into a designated folder for another application to pick up and process. But note that this has to be HL7 version 2.3.1 with the modifications made by Standards Australia. I have only just started writing this code and it has to be on a very much part time basis but I would be happy to share any code and any experiences.

There are later 2.x versions of the HL7 standard plus version 3 which is XML based.

The particular message I need to deal with (at this stage) is a REF. I have just started coding for the PID segment of that message. Whilst my primary need is to generate HL7 I will be writing code to both generate it and parse it.

I also note that it looks as if this application will have to switch to HL7 version 3 sometime in 2012.

I'm not sure from your message whether you need HL7 code or DICOM code or both.

Regards
xProgrammer
Post Reply